Merge pull request #1096 from barnettZQG/master

Structure adjustment #1083 #1084 #1085 #1086
This commit is contained in:
barnettZQG 2021-08-30 13:32:59 +08:00 committed by GitHub
commit c2f9930a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
392 changed files with 1489 additions and 22501 deletions

View File

@ -1,8 +1,8 @@
# Compile the project
```
# you must have docker and golang environment
if you have docker and golang environment
```
# build all docker image
make image
@ -12,11 +12,21 @@ make binary
# build binary for different os
GOOS=windows make binary
# if you what build one component
# if you what build one module
make binary WHAT=api
make image WHAT=api
```
in only golang environment
```
# build all module
./localbuild.sh all
# build one module
./localbuild.sh api
```
# How to contribute
Read [Contributing to Open Source on GitHub](https://guides.github.com/activities/contributing-to-open-source/) before contribute.

View File

@ -2,7 +2,6 @@ GO_LDFLAGS=-ldflags " -w"
VERSION=$(shell git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3)
WORK_DIR=/go/src/github.com/goodrain/rainbond
BASE_NAME=rainbond
BASE_DOCKER=./hack/contrib/docker
default: help
all: image ## build linux binaries, build images for docker

View File

@ -1,36 +0,0 @@
// 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 cloud
import (
"github.com/go-chi/chi"
"github.com/goodrain/rainbond/api/controller"
)
//Routes routes
func Routes() chi.Router {
r := chi.NewRouter()
r.Get("/show", controller.GetCloudRouterManager().Show)
r.Post("/auth", controller.GetCloudRouterManager().CreateToken)
r.Get("/auth/{eid}", controller.GetCloudRouterManager().GetTokenInfo)
r.Put("/auth/{eid}", controller.GetCloudRouterManager().UpdateToken)
r.Get("/api/manager", controller.GetCloudRouterManager().GetAPIManager)
r.Post("/api/manager", controller.GetCloudRouterManager().DeleteAPIManager)
return r
}

View File

@ -34,8 +34,6 @@ type V2 struct {
//Routes routes
func (v2 *V2) Routes() chi.Router {
r := chi.NewRouter()
license := middleware.NewLicense(v2.Cfg)
r.Use(license.Verify)
r.Get("/show", controller.GetManager().Show)
r.Post("/show", controller.GetManager().Show)
r.Mount("/tenants", v2.tenantRouter())

View File

@ -27,20 +27,15 @@ import (
//Routes routes
func Routes() chi.Router {
r := chi.NewRouter()
r.Get("/docker_console", controller.GetDockerConsole().Get)
r.Get("/docker_log", controller.GetDockerLog().Get)
r.Get("/monitor_message", controller.GetMonitorMessage().Get)
r.Get("/new_monitor_message", controller.GetMonitorMessage().Get)
r.Get("/event_log", controller.GetEventLog().Get)
r.Get("/services/{serviceID}/pubsub", controller.GetPubSubControll().Get)
return r
}
//LogRoutes 日志下载路由
//LogRoutes componet log download
func LogRoutes() chi.Router {
r := chi.NewRouter()
r.Get("/{gid}/{filename}", controller.GetLogFile().Get)
r.Get("/install_log/{filename}", controller.GetLogFile().GetInstallLog)
return r
}

View File

@ -1,241 +0,0 @@
// 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 controller
import (
"net/http"
"github.com/go-chi/chi"
"github.com/goodrain/rainbond/api/handler"
api_model "github.com/goodrain/rainbond/api/model"
httputil "github.com/goodrain/rainbond/util/http"
)
//CloudManager cloud manager
type CloudManager struct{}
var defaultCloudManager *CloudManager
//GetCloudRouterManager get cloud Manager
func GetCloudRouterManager() *CloudManager {
if defaultCloudManager != nil {
return defaultCloudManager
}
defaultCloudManager = &CloudManager{}
return defaultCloudManager
}
//Show Show
func (c *CloudManager) Show(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("cloud urls"))
}
//CreateToken CreateToken
// swagger:operation POST /cloud/auth cloud createToken
//
// 产生token
//
// create token
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) CreateToken(w http.ResponseWriter, r *http.Request) {
var gt api_model.GetUserToken
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &gt.Body, nil); !ok {
return
}
ti, err := handler.GetCloudManager().TokenDispatcher(&gt)
if err != nil {
err.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, ti)
}
//GetTokenInfo GetTokenInfo
// swagger:operation GET /cloud/auth/{eid} cloud getTokenInfo
//
// 获取tokeninfo
//
// get token info
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) GetTokenInfo(w http.ResponseWriter, r *http.Request) {
eid := chi.URLParam(r, "eid")
ti, err := handler.GetCloudManager().GetTokenInfo(eid)
if err != nil {
err.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, ti)
}
//UpdateToken UpdateToken
// swagger:operation PUT /cloud/auth/{eid} cloud updateToken
//
// 更新token
//
// update token info
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) UpdateToken(w http.ResponseWriter, r *http.Request) {
var ut api_model.UpdateToken
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &ut.Body, nil); !ok {
return
}
eid := chi.URLParam(r, "eid")
err := handler.GetCloudManager().UpdateTokenTime(eid, ut.Body.ValidityPeriod)
if err != nil {
err.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, nil)
}
//GetAPIManager GetAPIManager
// swagger:operation GET /cloud/api/manager cloud GetAPIManager
//
// 获取api管理
//
// get api manager
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) GetAPIManager(w http.ResponseWriter, r *http.Request) {
apiMap := handler.GetTokenIdenHandler().GetAPIManager()
httputil.ReturnSuccess(r, w, apiMap)
}
//AddAPIManager AddAPIManager
// swagger:operation POST /cloud/api/manager cloud addAPIManager
//
// 添加api管理
//
// get api manager
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) AddAPIManager(w http.ResponseWriter, r *http.Request) {
var am api_model.APIManager
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &am.Body, nil); !ok {
return
}
err := handler.GetTokenIdenHandler().AddAPIManager(&am)
if err != nil {
err.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, nil)
}
//DeleteAPIManager DeleteAPIManager
// swagger:operation DELETE /cloud/api/manager cloud deleteAPIManager
//
// 删除api管理
//
// delete api manager
//
// ---
// consumes:
// - application/json
// - application/x-protobuf
//
// produces:
// - application/json
// - application/xml
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (c *CloudManager) DeleteAPIManager(w http.ResponseWriter, r *http.Request) {
var am api_model.APIManager
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &am.Body, nil); !ok {
return
}
err := handler.GetTokenIdenHandler().DeleteAPIManager(&am)
if err != nil {
err.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, nil)
}

View File

@ -22,11 +22,9 @@ import (
"net/http"
"github.com/goodrain/rainbond/api/api"
"github.com/goodrain/rainbond/api/discover"
"github.com/goodrain/rainbond/api/proxy"
"github.com/goodrain/rainbond/cmd/api/option"
mqclient "github.com/goodrain/rainbond/mq/client"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/goodrain/rainbond/worker/client"
)
@ -66,13 +64,7 @@ func GetManager() V2Manager {
//NewManager new manager
func NewManager(conf option.Config, statusCli *client.AppRuntimeSyncClient) (*V2Routes, error) {
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: conf.EtcdEndpoint,
CaFile: conf.EtcdCaFile,
CertFile: conf.EtcdCertFile,
KeyFile: conf.EtcdKeyFile,
}
mqClient, err := mqclient.NewMqClient(etcdClientArgs, conf.MQAPI)
mqClient, err := mqclient.NewMqClient(conf.MQAPI)
if err != nil {
return nil, err
}
@ -82,8 +74,7 @@ func NewManager(conf option.Config, statusCli *client.AppRuntimeSyncClient) (*V2
v2r.GatewayStruct.MQClient = mqClient
v2r.GatewayStruct.cfg = &conf
v2r.LabelController.optconfig = &conf
eventServerProxy := proxy.CreateProxy("eventlog", "http", []string{"local=>rbd-eventlog:6363"})
discover.GetEndpointDiscover().AddProject("event_log_event_http", eventServerProxy)
eventServerProxy := proxy.CreateProxy("eventlog", "http", []string{"rbd-eventlog:6363"})
v2r.EventLogStruct.EventlogServerProxy = eventServerProxy
return &v2r, nil
}

View File

@ -19,13 +19,11 @@
package controller
import (
"context"
"net/http"
"os"
"path"
"github.com/go-chi/chi"
"github.com/goodrain/rainbond/api/discover"
"github.com/goodrain/rainbond/api/handler"
"github.com/goodrain/rainbond/api/proxy"
ctxutil "github.com/goodrain/rainbond/api/util/ctx"
@ -33,32 +31,7 @@ import (
"github.com/sirupsen/logrus"
)
//DockerConsole docker console
type DockerConsole struct {
socketproxy proxy.Proxy
}
var defaultDockerConsoleEndpoints = []string{"127.0.0.1:7171"}
var defaultEventLogEndpoints = []string{"local=>rbd-eventlog:6363"}
var dockerConsole *DockerConsole
//GetDockerConsole get Docker console
func GetDockerConsole() *DockerConsole {
if dockerConsole != nil {
return dockerConsole
}
dockerConsole = &DockerConsole{
socketproxy: proxy.CreateProxy("dockerconsole", "websocket", defaultDockerConsoleEndpoints),
}
discover.GetEndpointDiscover().AddProject("acp_webcli", dockerConsole.socketproxy)
return dockerConsole
}
//Get get
func (d DockerConsole) Get(w http.ResponseWriter, r *http.Request) {
d.socketproxy.Proxy(w, r)
}
var defaultEventLogEndpoints = []string{"rbd-eventlog:6363"}
var dockerLog *DockerLog
@ -73,7 +46,6 @@ func GetDockerLog() *DockerLog {
dockerLog = &DockerLog{
socketproxy: proxy.CreateProxy("dockerlog", "websocket", defaultEventLogEndpoints),
}
discover.GetEndpointDiscover().AddProject("event_log_event_http", dockerLog.socketproxy)
}
return dockerLog
}
@ -96,7 +68,6 @@ func GetMonitorMessage() *MonitorMessage {
monitorMessage = &MonitorMessage{
socketproxy: proxy.CreateProxy("monitormessage", "websocket", defaultEventLogEndpoints),
}
discover.GetEndpointDiscover().AddProject("event_log_event_http", monitorMessage.socketproxy)
}
return monitorMessage
}
@ -119,7 +90,6 @@ func GetEventLog() *EventLog {
eventLog = &EventLog{
socketproxy: proxy.CreateProxy("eventlog", "websocket", defaultEventLogEndpoints),
}
discover.GetEndpointDiscover().AddProject("event_log_event_http", eventLog.socketproxy)
}
return eventLog
}
@ -167,17 +137,6 @@ func isExist(filename string) bool {
return err == nil || os.IsExist(err)
}
// GetInstallLog get
func (d LogFile) GetInstallLog(w http.ResponseWriter, r *http.Request) {
filename := chi.URLParam(r, "filename")
filePath := d.Root + filename
if isExist(filePath) {
http.ServeFile(w, r, filePath)
} else {
w.WriteHeader(404)
}
}
var pubSubControll *PubSubControll
//PubSubControll service pub sub
@ -191,7 +150,6 @@ func GetPubSubControll() *PubSubControll {
pubSubControll = &PubSubControll{
socketproxy: proxy.CreateProxy("dockerlog", "websocket", defaultEventLogEndpoints),
}
discover.GetEndpointDiscover().AddProject("event_log_event_http", pubSubControll.socketproxy)
}
return pubSubControll
}
@ -199,10 +157,11 @@ func GetPubSubControll() *PubSubControll {
//Get pubsub controller
func (d PubSubControll) Get(w http.ResponseWriter, r *http.Request) {
serviceID := chi.URLParam(r, "serviceID")
name, _ := handler.GetEventHandler().GetLogInstance(serviceID)
if name != "" {
r.URL.Query().Add("host_id", name)
r = r.WithContext(context.WithValue(r.Context(), proxy.ContextKey("host_id"), name))
address, _ := handler.GetEventHandler().GetLogInstance(serviceID)
if address != "" {
logrus.Infof("pubsub websocket req proxy to eventlog instance %s", address)
proxy.CreateProxy("dockerlog", "websocket", []string{address}).Proxy(w, r)
return
}
d.socketproxy.Proxy(w, r)
}
@ -210,10 +169,11 @@ func (d PubSubControll) Get(w http.ResponseWriter, r *http.Request) {
//GetHistoryLog get service docker logs
func (d PubSubControll) GetHistoryLog(w http.ResponseWriter, r *http.Request) {
serviceID := r.Context().Value(ctxutil.ContextKey("service_id")).(string)
name, _ := handler.GetEventHandler().GetLogInstance(serviceID)
if name != "" {
r.URL.Query().Add("host_id", name)
r = r.WithContext(context.WithValue(r.Context(), proxy.ContextKey("host_id"), name))
address, _ := handler.GetEventHandler().GetLogInstance(serviceID)
if address != "" {
logrus.Infof("get history container log req proxy to eventlog instance %s", address)
proxy.CreateProxy("dockerlog", "websocket", []string{address}).Proxy(w, r)
return
}
d.socketproxy.Proxy(w, r)
}

View File

@ -1,65 +0,0 @@
// 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 daemon
import (
"github.com/goodrain/rainbond/api/util"
"net/http"
"os"
"os/exec"
"time"
"github.com/sirupsen/logrus"
)
//StartRegionAPI 启动
func StartRegionAPI(ch chan os.Signal) {
logrus.Info("old region api begin start..")
arg := []string{"region_api.wsgi", "-b=127.0.0.1:8887", "--max-requests=5000", "--reload", "--debug", "--workers=4", "--log-file", "-", "--access-logfile", "-", "--error-logfile", "-"}
cmd := exec.Command("gunicorn", arg...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
go func() {
if err := cmd.Start(); err != nil {
logrus.Error("start region old api error.", err.Error())
}
tick := time.NewTicker(time.Second * 5)
select {
case si := <-ch:
cmd.Process.Signal(si)
return
case <-tick.C:
monitor()
}
}()
return
}
func monitor() {
response, err := http.Get("http://127.0.0.1:8887/monitor")
if err != nil {
logrus.Error("monitor region old api error.", err.Error())
return
}
defer util.CloseResponse(response)
if response != nil && response.StatusCode/100 > 2 {
logrus.Errorf("monitor region old api error. response code is %s", response.Status)
}
}

View File

@ -31,7 +31,6 @@ import (
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
"github.com/goodrain/rainbond/mq/client"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/goodrain/rainbond/worker/discover/model"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
@ -65,17 +64,10 @@ func CreateDBManager(conf option.Config) error {
func CreateEventManager(conf option.Config) error {
var tryTime time.Duration
var err error
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: conf.EtcdEndpoint,
CaFile: conf.EtcdCaFile,
CertFile: conf.EtcdCertFile,
KeyFile: conf.EtcdKeyFile,
}
for tryTime < 4 {
tryTime++
if err = event.NewManager(event.EventConfig{
EventLogServers: conf.EventLogServers,
DiscoverArgs: etcdClientArgs,
}); err != nil {
logrus.Errorf("get event manager failed, try time is %v,%s", tryTime, err.Error())
time.Sleep((5 + tryTime*10) * time.Second)
@ -93,13 +85,12 @@ func CreateEventManager(conf option.Config) error {
//MQManager mq manager
type MQManager struct {
EtcdClientArgs *etcdutil.ClientArgs
DefaultServer string
DefaultServer string
}
//NewMQManager new mq manager
func (m *MQManager) NewMQManager() (client.MQClient, error) {
client, err := client.NewMqClient(m.EtcdClientArgs, m.DefaultServer)
client, err := client.NewMqClient(m.DefaultServer)
if err != nil {
logrus.Errorf("new mq manager error, %v", err)
return client, err

View File

@ -1,125 +0,0 @@
// 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 discover
import (
"errors"
"sync"
"github.com/goodrain/rainbond/api/proxy"
corediscover "github.com/goodrain/rainbond/discover"
corediscoverconfig "github.com/goodrain/rainbond/discover/config"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
//EndpointDiscover 后端服务自动发现
type EndpointDiscover interface {
AddProject(name string, proxy proxy.Proxy)
Remove(name string)
Stop()
}
var defaultEndpointDiscover EndpointDiscover
//CreateEndpointDiscover create endpoint discover
func CreateEndpointDiscover(etcdClientArgs *etcdutil.ClientArgs) (EndpointDiscover, error) {
if defaultEndpointDiscover == nil {
if etcdClientArgs == nil {
return nil, errors.New("etcd args is nil")
}
dis, err := corediscover.GetDiscover(corediscoverconfig.DiscoverConfig{EtcdClientArgs: etcdClientArgs})
if err != nil {
return nil, err
}
defaultEndpointDiscover = &endpointDiscover{
dis: dis,
projects: make(map[string]*defalt),
}
}
return defaultEndpointDiscover, nil
}
//GetEndpointDiscover get endpoints discover
func GetEndpointDiscover() EndpointDiscover {
return defaultEndpointDiscover
}
type endpointDiscover struct {
projects map[string]*defalt
lock sync.Mutex
dis corediscover.Discover
}
func (e *endpointDiscover) AddProject(name string, pro proxy.Proxy) {
e.lock.Lock()
defer e.lock.Unlock()
if def, ok := e.projects[name]; !ok {
e.projects[name] = &defalt{name: name, proxys: []proxy.Proxy{pro}}
e.dis.AddProject(name, e.projects[name])
} else {
def.proxys = append(def.proxys, pro)
// add proxy after update endpoint first,must initialize endpoint by cache data
if len(def.cacheEndpointURL) > 0 {
pro.UpdateEndpoints(def.cacheEndpointURL...)
}
}
}
func (e *endpointDiscover) Remove(name string) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; ok {
delete(e.projects, name)
}
}
func (e *endpointDiscover) Stop() {
e.dis.Stop()
}
type defalt struct {
name string
proxys []proxy.Proxy
cacheEndpointURL []string
}
func (e *defalt) Error(err error) {
logrus.Errorf("%s project auto discover occurred error.%s", e.name, err.Error())
defaultEndpointDiscover.Remove(e.name)
}
func (e *defalt) UpdateEndpoints(endpoints ...*corediscoverconfig.Endpoint) {
var endStr []string
for _, end := range endpoints {
if end.URL != "" {
endStr = append(endStr, end.Name+"=>"+end.URL)
}
}
logrus.Debugf("endstr is %v, name is %v", endStr, e.name)
for _, p := range e.proxys {
p.UpdateEndpoints(endStr...)
}
e.cacheEndpointURL = endStr
}
//when watch occurred error,will exec this method
func (e *endpointDiscover) Error(err error) {
logrus.Errorf("discover error %s", err.Error())
}

View File

@ -1,226 +0,0 @@
// 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 handler
import (
"crypto/md5"
crand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"time"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
api_model "github.com/goodrain/rainbond/api/model"
"github.com/goodrain/rainbond/api/util"
"github.com/goodrain/rainbond/cmd/api/option"
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
)
//CloudAction cloud action struct
type CloudAction struct {
RegionTag string
APISSL bool
CAPath string
KeyPath string
}
//CreateCloudManager get cloud manager
func CreateCloudManager(conf option.Config) *CloudAction {
return &CloudAction{
APISSL: conf.APISSL,
RegionTag: conf.RegionTag,
CAPath: conf.APICertFile,
KeyPath: conf.APIKeyFile,
}
}
//TokenDispatcher token
func (c *CloudAction) TokenDispatcher(gt *api_model.GetUserToken) (*api_model.TokenInfo, *util.APIHandleError) {
//TODO: product token, 启动api时需要添加该参数
//token包含 eid数据中心标识可控范围有效期
ti := &api_model.TokenInfo{
EID: gt.Body.EID,
}
token := c.createToken(gt)
var oldToken string
tokenInfos, err := db.GetManager().RegionUserInfoDao().GetTokenByEid(gt.Body.EID)
if err != nil {
if err.Error() == gorm.ErrRecordNotFound.Error() {
goto CREATE
}
return nil, util.CreateAPIHandleErrorFromDBError("get user token info", err)
}
ti.CA = tokenInfos.CA
//ti.Key = tokenInfos.Key
ti.Token = token
oldToken = tokenInfos.Token
tokenInfos.Token = token
tokenInfos.ValidityPeriod = gt.Body.ValidityPeriod
if err := db.GetManager().RegionUserInfoDao().UpdateModel(tokenInfos); err != nil {
return nil, util.CreateAPIHandleErrorFromDBError("recreate region user info", err)
}
tokenInfos.CA = ""
tokenInfos.Key = ""
GetTokenIdenHandler().DeleteTokenFromMap(oldToken, tokenInfos)
return ti, nil
CREATE:
ti.Token = token
logrus.Debugf("create token %v", token)
rui := &dbmodel.RegionUserInfo{
EID: gt.Body.EID,
RegionTag: c.RegionTag,
APIRange: gt.Body.Range,
ValidityPeriod: gt.Body.ValidityPeriod,
Token: token,
}
if c.APISSL {
ca, key, err := c.CertDispatcher(gt)
if err != nil {
return nil, util.CreateAPIHandleError(500, fmt.Errorf("create ca or key error"))
}
rui.CA = string(ca)
rui.Key = string(key)
ti.CA = string(ca)
//ti.Key = string(key)
}
if gt.Body.Range == "" {
rui.APIRange = dbmodel.SERVERSOURCE
}
GetTokenIdenHandler().AddTokenIntoMap(rui)
if err := db.GetManager().RegionUserInfoDao().AddModel(rui); err != nil {
return nil, util.CreateAPIHandleErrorFromDBError("create region user info", err)
}
return ti, nil
}
//GetTokenInfo GetTokenInfo
func (c *CloudAction) GetTokenInfo(eid string) (*dbmodel.RegionUserInfo, *util.APIHandleError) {
tokenInfos, err := db.GetManager().RegionUserInfoDao().GetTokenByEid(eid)
if err != nil {
return nil, util.CreateAPIHandleErrorFromDBError("get user token info", err)
}
return tokenInfos, nil
}
//UpdateTokenTime UpdateTokenTime
func (c *CloudAction) UpdateTokenTime(eid string, vd int) *util.APIHandleError {
tokenInfos, err := db.GetManager().RegionUserInfoDao().GetTokenByEid(eid)
if err != nil {
return util.CreateAPIHandleErrorFromDBError("get user token info", err)
}
tokenInfos.ValidityPeriod = vd
err = db.GetManager().RegionUserInfoDao().UpdateModel(tokenInfos)
if err != nil {
return util.CreateAPIHandleErrorFromDBError("update user token info", err)
}
return nil
}
//CertDispatcher Cert
func (c *CloudAction) CertDispatcher(gt *api_model.GetUserToken) ([]byte, []byte, error) {
cert, err := analystCaKey(c.CAPath, "ca")
if err != nil {
return nil, nil, err
}
//解析私钥
keyFile, err := analystCaKey(c.KeyPath, "key")
if err != nil {
return nil, nil, err
}
//keyFile = keyFile.(rsa.PrivateKey)
validHourTime := (gt.Body.ValidityPeriod - gt.Body.BeforeTime)
cer := &x509.Certificate{
SerialNumber: big.NewInt(1), //证书序列号
Subject: pkix.Name{
CommonName: fmt.Sprintf("%s@%d", gt.Body.EID, time.Now().Unix()),
Locality: []string{c.RegionTag},
},
NotBefore: time.Now(), //证书有效期开始时间
NotAfter: time.Now().Add(time.Second * time.Duration(validHourTime)), //证书有效期结束时间
BasicConstraintsValid: true, //基本的有效性约束
IsCA: false, //是否是根证书
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, //证书用途(客户端认证,数据加密)
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment,
//EmailAddresses: []string{"region@test.com"},
//IPAddresses: []net.IP{net.ParseIP("192.168.1.59")},
}
priKey, err := rsa.GenerateKey(crand.Reader, 2048)
if err != nil {
return nil, nil, err
}
ca, err := x509.CreateCertificate(crand.Reader, cer, cert.(*x509.Certificate), &priKey.PublicKey, keyFile)
if err != nil {
return nil, nil, err
}
//编码证书文件和私钥文件
caPem := &pem.Block{
Type: "CERTIFICATE",
Bytes: ca,
}
ca = pem.EncodeToMemory(caPem)
buf := x509.MarshalPKCS1PrivateKey(priKey)
keyPem := &pem.Block{
Type: "PRIVATE KEY",
Bytes: buf,
}
key := pem.EncodeToMemory(keyPem)
return ca, key, nil
}
func analystCaKey(path, kind string) (interface{}, error) {
fileInfo, err := ioutil.ReadFile(path)
if err != nil {
return "", nil
}
fileBlock, _ := pem.Decode(fileInfo)
switch kind {
case "ca":
cert, err := x509.ParseCertificate(fileBlock.Bytes)
if err != nil {
return "", nil
}
return cert, nil
case "key":
praKey, err := x509.ParsePKCS1PrivateKey(fileBlock.Bytes)
if err != nil {
return "", nil
}
return praKey, nil
}
return "", nil
}
func (c *CloudAction) createToken(gt *api_model.GetUserToken) string {
fullStr := fmt.Sprintf("%s-%s-%s-%d-%d", gt.Body.EID, c.RegionTag, gt.Body.Range, gt.Body.ValidityPeriod, int(time.Now().Unix()))
h := md5.New()
h.Write([]byte(fullStr))
return hex.EncodeToString(h.Sum(nil))
}

View File

@ -1,32 +0,0 @@
// 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 handler
import (
api_model "github.com/goodrain/rainbond/api/model"
"github.com/goodrain/rainbond/api/util"
dbmodel "github.com/goodrain/rainbond/db/model"
)
//CloudHandler define source handler
type CloudHandler interface {
TokenDispatcher(gt *api_model.GetUserToken) (*api_model.TokenInfo, *util.APIHandleError)
GetTokenInfo(eid string) (*dbmodel.RegionUserInfo, *util.APIHandleError)
UpdateTokenTime(eid string, vd int) *util.APIHandleError
}

View File

@ -21,32 +21,33 @@ package handler
import (
"bytes"
"compress/zlib"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"github.com/coreos/etcd/clientv3"
"github.com/goodrain/rainbond/api/model"
api_model "github.com/goodrain/rainbond/api/model"
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
eventdb "github.com/goodrain/rainbond/eventlog/db"
"github.com/goodrain/rainbond/util/constants"
"github.com/sirupsen/logrus"
)
//LogAction log action struct
type LogAction struct {
EtcdCli *clientv3.Client
eventdb *eventdb.EventFilePlugin
eventdb *eventdb.EventFilePlugin
eventLogServer string
}
//CreateLogManager get log manager
func CreateLogManager(cli *clientv3.Client) *LogAction {
func CreateLogManager() *LogAction {
return &LogAction{
EtcdCli: cli,
eventLogServer: "http://rbd-eventlog:6363",
eventdb: &eventdb.EventFilePlugin{
HomePath: "/grdata/logs/",
},
@ -97,15 +98,30 @@ func (l *LogAction) GetLogFile(serviceAlias, fileName string) (string, string, e
//GetLogInstance get log web socket instance
func (l *LogAction) GetLogInstance(serviceID string) (string, error) {
value, err := l.EtcdCli.Get(context.Background(), fmt.Sprintf("/event/dockerloginstacne/%s", serviceID))
if err != nil {
return "", err
retry := 1
for retry < 3 {
address := fmt.Sprintf("%s/docker-instance?service_id=%s&mode=stream", l.eventLogServer, serviceID)
res, err := http.DefaultClient.Get(address)
if res != nil && res.Body != nil {
defer res.Body.Close()
}
if err != nil {
logrus.Warningf("Error get host info from %s. %s", address, err)
retry++
continue
}
var host = make(map[string]interface{})
err = json.NewDecoder(res.Body).Decode(&host)
if err != nil {
logrus.Errorf("Error Decode BEST instance host info: %v", err)
retry++
continue
}
if status, ok := host["status"]; ok && status == "success" {
return fmt.Sprintf("%s:%d", host["ip"], int(host["websocket_port"].(float64))), nil
}
}
if len(value.Kvs) > 0 {
return string(value.Kvs[0].Value), nil
}
return "", nil
return "", fmt.Errorf("can not select docker log instance")
}
//GetLevelLog get event log

View File

@ -33,21 +33,6 @@ import (
var gm *GatewayAction
func init() {
//conf := option.Config{
// DBType: "mysql",
// DBConnectionInfo: "pohF4b:EiW6Eipu@tcp(192.168.56.101:3306)/region",
//}
////创建db manager
//if err := db.CreateDBManager(conf); err != nil {
// fmt.Printf("create db manager error, %v", err)
//}
//cli, err := client.NewMqClient([]string{"http://192.168.56.101:2379"}, "192.168.56.101:6300")
//if err != nil {
// fmt.Printf("create mq client error, %v", err)
//}
//gm = CreateGatewayManager(cdb.GetManager(), cli, nil)
}
func TestSelectAvailablePort(t *testing.T) {
t.Log(selectAvailablePort([]int{9000})) // less than minport
t.Log(selectAvailablePort([]int{10000})) // equal to minport

View File

@ -44,8 +44,7 @@ func InitHandle(conf option.Config,
k8sClient k8sclient.Client,
) error {
mq := api_db.MQManager{
EtcdClientArgs: etcdClientArgs,
DefaultServer: conf.MQAPI,
DefaultServer: conf.MQAPI,
}
mqClient, errMQ := mq.NewMQManager()
if errMQ != nil {
@ -65,9 +64,8 @@ func InitHandle(conf option.Config,
defaultAppHandler = CreateAppManager(mqClient)
defaultTenantHandler = CreateTenManager(mqClient, statusCli, &conf, kubeClient, prometheusCli, k8sClient)
defaultNetRulesHandler = CreateNetRulesManager(etcdcli)
defaultCloudHandler = CreateCloudManager(conf)
defaultAPPBackupHandler = group.CreateBackupHandle(mqClient, statusCli, etcdcli)
defaultEventHandler = CreateLogManager(etcdcli)
defaultEventHandler = CreateLogManager()
shareHandler = &share.ServiceShareHandle{MQClient: mqClient, EtcdCli: etcdcli}
pluginShareHandler = &share.PluginShareHandle{MQClient: mqClient, EtcdCli: etcdcli}
if err := CreateTokenIdenHandler(conf); err != nil {
@ -135,13 +133,6 @@ func GetRulesManager() NetRulesHandler {
return defaultNetRulesHandler
}
var defaultCloudHandler CloudHandler
//GetCloudManager get manager
func GetCloudManager() CloudHandler {
return defaultCloudHandler
}
var defaultEventHandler EventHandler
//GetEventHandler get event handler

View File

@ -19,43 +19,27 @@
package handler
import (
"github.com/goodrain/rainbond/api/discover"
"github.com/goodrain/rainbond/api/proxy"
"github.com/goodrain/rainbond/cmd/api/option"
)
var nodeProxy proxy.Proxy
var builderProxy proxy.Proxy
var prometheusProxy proxy.Proxy
var monitorProxy proxy.Proxy
var kubernetesDashboard proxy.Proxy
//InitProxy 初始化
func InitProxy(conf option.Config) {
if nodeProxy == nil {
nodeProxy = proxy.CreateProxy("acp_node", "http", conf.NodeAPI)
discover.GetEndpointDiscover().AddProject("acp_node", nodeProxy)
}
if builderProxy == nil {
builderProxy = proxy.CreateProxy("builder", "http", conf.BuilderAPI)
}
if prometheusProxy == nil {
prometheusProxy = proxy.CreateProxy("prometheus", "http", []string{conf.PrometheusEndpoint})
}
if monitorProxy == nil {
monitorProxy = proxy.CreateProxy("monitor", "http", []string{"127.0.0.1:3329"})
discover.GetEndpointDiscover().AddProject("monitor", monitorProxy)
}
if kubernetesDashboard == nil {
kubernetesDashboard = proxy.CreateProxy("kubernetesdashboard", "http", []string{conf.KuberentesDashboardAPI})
}
}
//GetNodeProxy GetNodeProxy
func GetNodeProxy() proxy.Proxy {
return nodeProxy
}
//GetBuilderProxy GetNodeProxy
func GetBuilderProxy() proxy.Proxy {
return builderProxy
@ -66,11 +50,6 @@ func GetPrometheusProxy() proxy.Proxy {
return prometheusProxy
}
//GetMonitorProxy GetMonitorProxy
func GetMonitorProxy() proxy.Proxy {
return monitorProxy
}
// GetKubernetesDashboardProxy returns the kubernetes dashboard proxy.
func GetKubernetesDashboardProxy() proxy.Proxy {
return kubernetesDashboard

View File

@ -2347,10 +2347,12 @@ func (s *ServiceAction) ListVersionInfo(serviceID string) (*api_model.BuildListR
for idx := range bversions {
bv := bversions[idx]
if bv.Kind == "build_from_image" || bv.Kind == "build_from_market_image" {
image := parser.ParseImageName(bv.RepoURL)
bv.ImageDomain = image.GetDomain()
bv.ImageRepo = image.GetRepostory()
bv.ImageTag = image.GetTag()
if bv.RepoURL != "" {
image := parser.ParseImageName(bv.RepoURL)
bv.ImageDomain = image.GetDomain()
bv.ImageRepo = image.GetRepostory()
bv.ImageTag = image.GetTag()
}
}
}
result := &api_model.BuildListRespVO{

View File

@ -60,6 +60,7 @@ func CreateOperationHandler(mqCli gclient.MQClient) *OperationHandler {
func (o *OperationHandler) Build(batchOpReq model.ComponentOpReq) (*model.ComponentOpResult, error) {
res := batchOpReq.BatchOpFailureItem()
if err := o.build(batchOpReq); err != nil {
logrus.Errorf("build component failure %s", err.Error())
res.ErrMsg = err.Error()
} else {
res.Success()
@ -279,7 +280,6 @@ func (o *OperationHandler) buildFromMarketSlug(r *model.ComponentBuildReq, servi
return o.sendBuildTopic(service.ServiceID, "build_from_market_slug", body)
}
func (o *OperationHandler) sendBuildTopic(serviceID, taskType string, body map[string]interface{}) error {
topic := gclient.BuilderTopic
if o.isWindowsService(serviceID) {
topic = gclient.WindowsBuilderTopic

View File

@ -30,7 +30,7 @@ import (
// Metric name parts.
const (
// Namespace for all metrics.
namespace = "rbd_api"
namespace = "region_api"
// Subsystem(s).
exporter = "exporter"
)

View File

@ -1,37 +0,0 @@
package middleware
import (
"net/http"
"github.com/goodrain/rainbond/cmd/api/option"
httputil "github.com/goodrain/rainbond/util/http"
licutil "github.com/goodrain/rainbond/util/license"
)
// License -
type License struct {
cfg *option.Config
}
// NewLicense -
func NewLicense(cfg *option.Config) *License {
return &License{
cfg: cfg,
}
}
// Verify parses the license to make the content inside it take effect.
func (l *License) Verify(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !licutil.VerifyTime(l.cfg.LicensePath, l.cfg.LicSoPath) {
httputil.Return(r, w, 401, httputil.ResponseBody{
Bean: map[string]interface{}{
"msg": "invalid license",
"code": 10400,
},
})
return
}
next.ServeHTTP(w, r)
})
}

View File

@ -162,38 +162,10 @@ func SetLog(next http.Handler) http.Handler {
//Proxy 反向代理中间件
func Proxy(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.RequestURI, "/v2/nodes") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/cluster/service-health") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/builder") {
handler.GetBuilderProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/tasks") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/tasktemps") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/taskgroups") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/configs") {
handler.GetNodeProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/v2/rules") {
handler.GetMonitorProxy().Proxy(w, r)
return
}
if strings.HasPrefix(r.RequestURI, "/kubernetes/dashboard") {
proxy := handler.GetKubernetesDashboardProxy()
r.URL.Path = strings.Replace(r.URL.Path, "/kubernetes/dashboard", "", 1)

View File

@ -22,8 +22,6 @@ import (
"net/http"
"strings"
"sync/atomic"
"github.com/sirupsen/logrus"
)
//ContextKey context key
@ -147,50 +145,3 @@ func (rr RoundRobin) Select(r *http.Request, endpoints EndpointList) Endpoint {
selec := int(atomic.AddUint64(rr.ops, 1) % l)
return endpoints.Selec(selec)
}
//SelectBalance 选择性负载均衡
type SelectBalance struct {
hostIDMap map[string]string
}
//NewSelectBalance 创建选择性负载均衡
func NewSelectBalance() *SelectBalance {
return &SelectBalance{
hostIDMap: map[string]string{"local": "rbd-eventlog:6363"},
}
}
//Select 负载
func (s *SelectBalance) Select(r *http.Request, endpoints EndpointList) Endpoint {
if r.URL == nil {
return Endpoint(s.hostIDMap["local"])
}
id2ip := map[string]string{"local": "rbd-eventlog:6363"}
for _, end := range endpoints {
if kv := strings.Split(string(end), "=>"); len(kv) > 1 {
id2ip[kv[0]] = kv[1]
}
}
if r.URL != nil {
hostID := r.URL.Query().Get("host_id")
if hostID == "" {
hostIDFromContext := r.Context().Value(ContextKey("host_id"))
if hostIDFromContext != nil {
hostID = hostIDFromContext.(string)
}
}
if e, ok := id2ip[hostID]; ok {
logrus.Infof("[lb selelct] find host %s from name %s success", e, hostID)
return Endpoint(e)
}
}
if len(endpoints) > 0 {
logrus.Infof("default endpoint is %s", endpoints[len(endpoints)-1])
return endpoints[len(endpoints)-1]
}
return Endpoint(s.hostIDMap["local"])
}

View File

@ -23,11 +23,6 @@ import (
"testing"
)
func TestNewSelectBalance(t *testing.T) {
sb := NewSelectBalance()
t.Log(sb.hostIDMap)
}
func TestURLParse(t *testing.T) {
endURL, err := url.Parse("127.0.0.1:8080")
if err != nil {

View File

@ -33,9 +33,6 @@ func CreateProxy(name string, mode string, endpoints []string) Proxy {
case "websocket":
return createWebSocketProxy(name, endpoints)
case "http":
if name == "eventlog" {
return createHTTPProxy(name, endpoints, NewSelectBalance())
}
return createHTTPProxy(name, endpoints, nil)
default:
return createHTTPProxy(name, endpoints, nil)

View File

@ -162,17 +162,9 @@ func (h *WebSocketProxy) Do(r *http.Request) (*http.Response, error) {
}
func createWebSocketProxy(name string, endpoints []string) *WebSocketProxy {
if name != "dockerlog" {
return &WebSocketProxy{
name: name,
endpoints: CreateEndpoints(endpoints),
lb: NewRoundRobin(),
}
}
return &WebSocketProxy{
name: name,
endpoints: CreateEndpoints(endpoints),
lb: NewSelectBalance(),
lb: NewRoundRobin(),
}
}

View File

@ -1,102 +0,0 @@
// 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 region
// //DefineCloudAuth DefineCloudAuth
// func (t *tenant) DefineCloudAuth(gt *api_model.GetUserToken) DefineCloudAuthInterface {
// return &DefineCloudAuth{
// GT: gt,
// }
// }
// //DefineCloudAuth DefineCloudAuth
// type DefineCloudAuth struct {
// GT *api_model.GetUserToken
// }
// //DefineCloudAuthInterface DefineCloudAuthInterface
// type DefineCloudAuthInterface interface {
// GetToken() ([]byte, error)
// PostToken() ([]byte, error)
// PutToken() error
// }
// //GetToken GetToken
// func (d *DefineCloudAuth) GetToken() ([]byte, error) {
// resp, code, err := request(
// fmt.Sprintf("/cloud/auth/%s", d.GT.Body.EID),
// "GET",
// nil,
// )
// if err != nil {
// return nil, util.CreateAPIHandleError(code, err)
// }
// if code > 400 {
// if code == 404 {
// return nil, util.CreateAPIHandleError(code, fmt.Errorf("eid %s is not exist", d.GT.Body.EID))
// }
// return nil, util.CreateAPIHandleError(code, fmt.Errorf("get eid infos %s failed", d.GT.Body.EID))
// }
// //valJ, err := simplejson.NewJson(resp)
// return resp, nil
// }
// //PostToken PostToken
// func (d *DefineCloudAuth) PostToken() ([]byte, error) {
// data, err := ffjson.Marshal(d.GT.Body)
// if err != nil {
// return nil, err
// }
// resp, code, err := request(
// "/cloud/auth",
// "POST",
// data,
// )
// if err != nil {
// logrus.Errorf("create auth token error, %v", err)
// return nil, util.CreateAPIHandleError(code, err)
// }
// if code > 400 {
// logrus.Errorf("create auth token error")
// return nil, util.CreateAPIHandleError(code, fmt.Errorf("cretae auth token failed"))
// }
// return resp, nil
// }
// //PutToken PutToken
// func (d *DefineCloudAuth) PutToken() error {
// data, err := ffjson.Marshal(d.GT.Body)
// if err != nil {
// return err
// }
// _, code, err := request(
// fmt.Sprintf("/cloud/auth/%s", d.GT.Body.EID),
// "PUT",
// data,
// )
// if err != nil {
// logrus.Errorf("create auth token error, %v", err)
// return util.CreateAPIHandleError(code, err)
// }
// if code > 400 {
// logrus.Errorf("create auth token error")
// return util.CreateAPIHandleError(code, fmt.Errorf("cretae auth token failed"))
// }
// return nil
// }

View File

@ -20,13 +20,34 @@ package region
import (
"github.com/goodrain/rainbond/api/util"
"github.com/goodrain/rainbond/node/api/model"
utilhttp "github.com/goodrain/rainbond/util/http"
)
//ClusterResource cluster resource model
type ClusterResource struct {
AllNode int `json:"all_node"`
NotReadyNode int `json:"notready_node"`
ComputeNode int `json:"compute_node"`
Tenant int `json:"tenant"`
CapCPU int `json:"cap_cpu"` //可分配CPU总额
CapMem int `json:"cap_mem"` //可分配Mem总额
HealthCapCPU int `json:"health_cap_cpu"` //健康可分配CPU
HealthCapMem int `json:"health_cap_mem"` //健康可分配Mem
UnhealthCapCPU int `json:"unhealth_cap_cpu"` //不健康可分配CPU
UnhealthCapMem int `json:"unhealth_cap_mem"` //不健康可分配Mem
ReqCPU float32 `json:"req_cpu"` //已使用CPU总额
ReqMem int `json:"req_mem"` //已使用Mem总额
HealthReqCPU float32 `json:"health_req_cpu"` //健康已使用CPU
HealthReqMem int `json:"health_req_mem"` //健康已使用Mem
UnhealthReqCPU float32 `json:"unhealth_req_cpu"` //不健康已使用CPU
UnhealthReqMem int `json:"unhealth_req_mem"` //不健康已使用Mem
CapDisk uint64 `json:"cap_disk"`
ReqDisk uint64 `json:"req_disk"`
}
//ClusterInterface cluster api
type ClusterInterface interface {
GetClusterInfo() (*model.ClusterResource, *util.APIHandleError)
GetClusterInfo() (*ClusterResource, *util.APIHandleError)
GetClusterHealth() (*utilhttp.ResponseBody, *util.APIHandleError)
}
@ -39,8 +60,8 @@ type cluster struct {
prefix string
}
func (c *cluster) GetClusterInfo() (*model.ClusterResource, *util.APIHandleError) {
var cr model.ClusterResource
func (c *cluster) GetClusterInfo() (*ClusterResource, *util.APIHandleError) {
var cr ClusterResource
var decode utilhttp.ResponseBody
decode.Bean = &cr
code, err := c.DoRequest(c.prefix, "GET", nil, &decode)

View File

@ -1,164 +0,0 @@
// 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 region
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/goodrain/rainbond/api/util"
"github.com/goodrain/rainbond/node/api/model"
utilhttp "github.com/goodrain/rainbond/util/http"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
)
// MonitorInterface cluster api
type MonitorInterface interface {
GetRule(name string) (*model.AlertingNameConfig, *util.APIHandleError)
GetAllRule() (*model.AlertingRulesConfig, *util.APIHandleError)
DelRule(name string) (*utilhttp.ResponseBody, *util.APIHandleError)
AddRule(path string) (*utilhttp.ResponseBody, *util.APIHandleError)
RegRule(ruleName string, path string) (*utilhttp.ResponseBody, *util.APIHandleError)
}
func (r *regionImpl) Monitor() MonitorInterface {
return &monitor{prefix: "/v2/rules", regionImpl: *r}
}
type monitor struct {
regionImpl
prefix string
}
func (m *monitor) GetRule(name string) (*model.AlertingNameConfig, *util.APIHandleError) {
var ac model.AlertingNameConfig
var decode utilhttp.ResponseBody
decode.Bean = &ac
code, err := m.DoRequest(m.prefix+"/"+name, "GET", nil, &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Bean)
return nil, util.CreateAPIHandleError(code, fmt.Errorf("get alerting rules error code %d", code))
}
return &ac, nil
}
func (m *monitor) GetAllRule() (*model.AlertingRulesConfig, *util.APIHandleError) {
var ac model.AlertingRulesConfig
var decode utilhttp.ResponseBody
decode.Bean = &ac
code, err := m.DoRequest(m.prefix+"/all", "GET", nil, &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Bean)
return nil, util.CreateAPIHandleError(code, fmt.Errorf("get alerting rules error code %d", code))
}
return &ac, nil
}
func (m *monitor) DelRule(name string) (*utilhttp.ResponseBody, *util.APIHandleError) {
var decode utilhttp.ResponseBody
code, err := m.DoRequest(m.prefix+"/"+name, "DELETE", nil, &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Bean)
return nil, util.CreateAPIHandleError(code, fmt.Errorf("del alerting rules error code %d", code))
}
return &decode, nil
}
func (m *monitor) AddRule(path string) (*utilhttp.ResponseBody, *util.APIHandleError) {
_, err := os.Stat(path)
if err != nil {
if !os.IsExist(err) {
return nil, util.CreateAPIHandleError(400, errors.New("file does not exist"))
}
}
content, err := ioutil.ReadFile(path)
if err != nil {
logrus.Error("Failed to read AlertingRules config file: ", err.Error())
return nil, util.CreateAPIHandleError(400, err)
}
var rulesConfig model.AlertingNameConfig
if err := yaml.Unmarshal(content, &rulesConfig); err != nil {
logrus.Error("Unmarshal AlertingRulesConfig config string to object error.", err.Error())
return nil, util.CreateAPIHandleError(400, err)
}
var decode utilhttp.ResponseBody
body, err := json.Marshal(rulesConfig)
if err != nil {
return nil, util.CreateAPIHandleError(400, err)
}
code, err := m.DoRequest(m.prefix, "POST", bytes.NewBuffer(body), &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Bean)
return nil, util.CreateAPIHandleError(code, fmt.Errorf("add alerting rules error code %d", code))
}
return &decode, nil
}
func (m *monitor) RegRule(ruleName string, path string) (*utilhttp.ResponseBody, *util.APIHandleError) {
_, err := os.Stat(path)
if err != nil {
if !os.IsExist(err) {
return nil, util.CreateAPIHandleError(400, errors.New("file does not exist"))
}
}
content, err := ioutil.ReadFile(path)
if err != nil {
logrus.Error("Failed to read AlertingRules config file: ", err.Error())
return nil, util.CreateAPIHandleError(400, err)
}
var rulesConfig model.AlertingNameConfig
if err := yaml.Unmarshal(content, &rulesConfig); err != nil {
logrus.Error("Unmarshal AlertingRulesConfig config string to object error.", err.Error())
return nil, util.CreateAPIHandleError(400, err)
}
var decode utilhttp.ResponseBody
body, err := json.Marshal(rulesConfig)
if err != nil {
return nil, util.CreateAPIHandleError(400, err)
}
code, err := m.DoRequest(m.prefix+"/"+ruleName, "PUT", bytes.NewBuffer(body), &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Bean)
return nil, util.CreateAPIHandleError(code, fmt.Errorf("add alerting rules error code %d", code))
}
return &decode, nil
}

View File

@ -1,369 +0,0 @@
// 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 region
import (
"bytes"
"encoding/json"
"fmt"
"github.com/goodrain/rainbond/node/api/model"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/pquerna/ffjson/ffjson"
//"github.com/goodrain/rainbond/grctl/cmd"
"github.com/goodrain/rainbond/api/util"
utilhttp "github.com/goodrain/rainbond/util/http"
)
func (r *regionImpl) Nodes() NodeInterface {
return &node{regionImpl: *r, prefix: "/v2/nodes"}
}
func (r *regionImpl) Configs() ConfigsInterface {
return &configs{regionImpl: *r, prefix: "/v2/configs"}
}
type task struct {
regionImpl
prefix string
}
type node struct {
regionImpl
prefix string
}
func (n *node) Get(node string) (*client.HostNode, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc client.HostNode
res.Bean = &gc
code, err := n.DoRequest(n.prefix+"/"+node, "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Get node detail code %d", code))
}
return &gc, nil
}
func (n *node) GetNodeResource(node string) (*client.NodePodResource, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc client.NodePodResource
res.Bean = &gc
code, err := n.DoRequest(n.prefix+"/"+node+"/resource", "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Get node resource code %d", code))
}
return &gc, nil
}
func (n *node) GetNodeByRule(rule string) ([]*client.HostNode, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc []*client.HostNode
res.List = &gc
code, err := n.DoRequest(n.prefix+"/rule/"+rule, "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Get node rule code %d", code))
}
return gc, nil
}
func (n *node) UpdateNodeStatus(nid, status string) (*client.HostNode, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc client.HostNode
res.Bean = &gc
req := fmt.Sprintf(`{"status":"%s"}`, status)
code, err := n.DoRequest(n.prefix+"/"+nid+"/status", "PUT", bytes.NewBuffer([]byte(req)), &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Update node status failure code %d", code))
}
return &gc, nil
}
func (n *node) List() ([]*client.HostNode, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc []*client.HostNode
res.List = &gc
code, err := n.DoRequest(n.prefix, "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Get node list code %d", code))
}
return gc, nil
}
func (n *node) GetAllNodeHealth() (map[string][]map[string]string, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc map[string][]map[string]string
res.Bean = &gc
code, err := n.DoRequest(n.prefix+"/all_node_health", "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
if code != 200 {
return nil, util.CreateAPIHandleError(code, fmt.Errorf("Get node health code %d", code))
}
return gc, nil
}
func (n *node) Add(node *client.APIHostNode) (*client.HostNode, *util.APIHandleError) {
body, err := json.Marshal(node)
if err != nil {
return nil, util.CreateAPIHandleError(400, err)
}
var res utilhttp.ResponseBody
var renode client.HostNode
res.Bean = &renode
code, err := n.DoRequest(n.prefix, "POST", bytes.NewBuffer(body), &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
return &renode, handleAPIResult(code, res)
}
func (n *node) Label(nid string) NodeLabelInterface {
return &nodeLabelImpl{nodeImpl: n, NodeID: nid}
}
func (n *node) Condition(nid string) NodeConditionInterface {
return &nodeConditionImpl{nodeImpl: n, NodeID: nid}
}
type nodeLabelImpl struct {
nodeImpl *node
NodeID string
}
func (nl *nodeLabelImpl) List() (map[string]string, *util.APIHandleError) {
var decode map[string]string
var res utilhttp.ResponseBody
res.Bean = &decode
code, err := nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/labels", "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
return decode, handleAPIResult(code, res)
}
func (nl *nodeLabelImpl) Delete(k string) *util.APIHandleError {
var decode map[string]string
var res utilhttp.ResponseBody
res.Bean = &decode
code, err := nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/labels", "GET", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
if handleAPIResult(code, res) != nil {
return handleAPIResult(code, res)
}
delete(decode, k)
body, err := json.Marshal(decode)
if err != nil {
return util.CreateAPIHandleError(400, err)
}
code, err = nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/labels", "PUT", bytes.NewBuffer(body), &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (nl *nodeLabelImpl) Add(k, v string) *util.APIHandleError {
var decode map[string]string
var res utilhttp.ResponseBody
res.Bean = &decode
code, err := nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/labels", "GET", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
if handleAPIResult(code, res) != nil {
return handleAPIResult(code, res)
}
decode[k] = v
body, err := json.Marshal(decode)
if err != nil {
return util.CreateAPIHandleError(400, err)
}
code, err = nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/labels", "PUT", bytes.NewBuffer(body), &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
type nodeConditionImpl struct {
nodeImpl *node
NodeID string
}
func (nl *nodeConditionImpl) List() ([]client.NodeCondition, *util.APIHandleError) {
var decode []client.NodeCondition
var res utilhttp.ResponseBody
res.List = &decode
code, err := nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/conditions", "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
return decode, handleAPIResult(code, res)
}
func (nl *nodeConditionImpl) Delete(k client.NodeConditionType) ([]client.NodeCondition, *util.APIHandleError) {
var decode []client.NodeCondition
var res utilhttp.ResponseBody
res.List = &decode
code, err := nl.nodeImpl.DoRequest(nl.nodeImpl.prefix+"/"+nl.NodeID+"/conditions/"+string(k), "DELETE", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
return decode, handleAPIResult(code, res)
}
func (n *node) Delete(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid, "DELETE", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (n *node) Up(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid+"/up", "POST", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (n *node) Down(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid+"/down", "POST", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (n *node) UnSchedulable(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid+"/unschedulable", "PUT", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (n *node) ReSchedulable(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid+"/reschedulable", "PUT", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
func (n *node) Install(nid string) *util.APIHandleError {
var res utilhttp.ResponseBody
code, err := n.DoRequest(n.prefix+"/"+nid+"/install", "POST", nil, &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
type configs struct {
regionImpl
prefix string
}
func (c *configs) Get() (*model.GlobalConfig, *util.APIHandleError) {
var res utilhttp.ResponseBody
var gc = model.GlobalConfig{
Configs: make(map[string]*model.ConfigUnit),
}
res.Bean = &gc
code, err := c.DoRequest(c.prefix+"/datacenter", "GET", nil, &res)
if err != nil {
return nil, util.CreateAPIHandleError(code, err)
}
return &gc, handleAPIResult(code, res)
}
func (c *configs) Put(gc *model.GlobalConfig) *util.APIHandleError {
rebody, err := ffjson.Marshal(gc)
if err != nil {
return util.CreateAPIHandleError(400, err)
}
var res utilhttp.ResponseBody
code, err := c.DoRequest(c.prefix+"/datacenter", "PUT", bytes.NewBuffer(rebody), &res)
if err != nil {
return util.CreateAPIHandleError(code, err)
}
return handleAPIResult(code, res)
}
//TaskInterface task api
type TaskInterface interface {
Get(name string) (*model.Task, *util.APIHandleError)
GetTaskStatus(task string) (map[string]*model.TaskStatus, *util.APIHandleError)
Add(task *model.Task) *util.APIHandleError
AddGroup(group *model.TaskGroup) *util.APIHandleError
Exec(name string, nodes []string) *util.APIHandleError
List() ([]*model.Task, *util.APIHandleError)
}
//NodeInterface node api
type NodeInterface interface {
GetNodeByRule(rule string) ([]*client.HostNode, *util.APIHandleError)
Get(node string) (*client.HostNode, *util.APIHandleError)
GetNodeResource(node string) (*client.NodePodResource, *util.APIHandleError)
List() ([]*client.HostNode, *util.APIHandleError)
GetAllNodeHealth() (map[string][]map[string]string, *util.APIHandleError)
Add(node *client.APIHostNode) (*client.HostNode, *util.APIHandleError)
Up(nid string) *util.APIHandleError
Down(nid string) *util.APIHandleError
UnSchedulable(nid string) *util.APIHandleError
ReSchedulable(nid string) *util.APIHandleError
Delete(nid string) *util.APIHandleError
Label(nid string) NodeLabelInterface
Condition(nid string) NodeConditionInterface
Install(nid string) *util.APIHandleError
UpdateNodeStatus(nid, status string) (*client.HostNode, *util.APIHandleError)
}
//NodeLabelInterface node label interface
type NodeLabelInterface interface {
Add(k, v string) *util.APIHandleError
Delete(k string) *util.APIHandleError
List() (map[string]string, *util.APIHandleError)
}
//NodeConditionInterface node condition manage api
type NodeConditionInterface interface {
List() ([]client.NodeCondition, *util.APIHandleError)
Delete(conditionType client.NodeConditionType) ([]client.NodeCondition, *util.APIHandleError)
}
//ConfigsInterface 数据中心配置API
type ConfigsInterface interface {
Get() (*model.GlobalConfig, *util.APIHandleError)
Put(*model.GlobalConfig) *util.APIHandleError
}

View File

@ -1,77 +0,0 @@
// 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 region
import (
"bytes"
"encoding/json"
"fmt"
"github.com/goodrain/rainbond/api/util"
"github.com/goodrain/rainbond/node/api/model"
utilhttp "github.com/goodrain/rainbond/util/http"
"github.com/sirupsen/logrus"
)
//NotificationInterface cluster api
type NotificationInterface interface {
GetNotification(start string, end string) ([]*model.NotificationEvent, *util.APIHandleError)
HandleNotification(serviceName string, message string) ([]*model.NotificationEvent, *util.APIHandleError)
}
func (r *regionImpl) Notification() NotificationInterface {
return &notification{prefix: "/v2/notificationEvent", regionImpl: *r}
}
type notification struct {
regionImpl
prefix string
}
func (n *notification) GetNotification(start string, end string) ([]*model.NotificationEvent, *util.APIHandleError) {
var ne []*model.NotificationEvent
var decode utilhttp.ResponseBody
decode.List = &ne
code, err := n.DoRequest(n.prefix+"?start="+start+"&"+"end="+end, "GET", nil, &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Msg)
return nil, util.CreateAPIHandleError(code, fmt.Errorf(decode.Msg))
}
return ne, nil
}
func (n *notification) HandleNotification(serviceName string, message string) ([]*model.NotificationEvent, *util.APIHandleError) {
var ne []*model.NotificationEvent
var decode utilhttp.ResponseBody
decode.List = &ne
handleMessage, err := json.Marshal(map[string]string{"handle_message": message})
body := bytes.NewBuffer(handleMessage)
code, err := n.DoRequest(n.prefix+"/"+serviceName, "PUT", body, &decode)
if err != nil {
return nil, handleErrAndCode(err, code)
}
if code != 200 {
logrus.Error("Return failure message ", decode.Msg)
return nil, util.CreateAPIHandleError(code, fmt.Errorf(decode.Msg))
}
return ne, nil
}

View File

@ -48,12 +48,8 @@ var AllTenant string
type Region interface {
Tenants(name string) TenantInterface
Resources() ResourcesInterface
Nodes() NodeInterface
Cluster() ClusterInterface
Configs() ConfigsInterface
Version() string
Monitor() MonitorInterface
Notification() NotificationInterface
DoRequest(path, method string, body io.Reader, decode *utilhttp.ResponseBody) (int, error)
}

View File

@ -1,102 +0,0 @@
// 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 region
import (
"testing"
dbmodel "github.com/goodrain/rainbond/db/model"
utilhttp "github.com/goodrain/rainbond/util/http"
)
func TestListTenant(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"http://kubeapi.goodrain.me:8888"},
})
tenants, err := region.Tenants("").List()
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", tenants)
}
func TestListServices(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"http://kubeapi.goodrain.me:8888"},
})
services, err := region.Tenants("n93lkp7t").Services("").List()
if err != nil {
t.Fatal(err)
}
for _, s := range services {
t.Logf("%+v", s)
}
}
func TestDoRequest(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"http://kubeapi.goodrain.me:8888"},
})
var decode utilhttp.ResponseBody
var tenants []*dbmodel.Tenants
decode.List = &tenants
code, err := region.DoRequest("/v2/tenants", "GET", nil, &decode)
if err != nil {
t.Fatal(err, code)
}
t.Logf("%+v", tenants)
}
func TestListNodes(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"http://kubeapi.goodrain.me:8888"},
})
services, err := region.Nodes().List()
if err != nil {
t.Fatal(err)
}
for _, s := range services {
t.Logf("%+v", s)
}
}
func TestGetNodes(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"http://kubeapi.goodrain.me:8888"},
})
node, err := region.Nodes().Get("a134eab8-3d42-40f5-84a5-fcf2b7a44b31")
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", node)
}
func TestGetTenantsBySSL(t *testing.T) {
region, _ := NewRegion(APIConf{
Endpoints: []string{"https://127.0.0.1:8443"},
Cacert: "/Users/qingguo/gopath/src/github.com/goodrain/rainbond/test/ssl/ca.pem",
Cert: "/Users/qingguo/gopath/src/github.com/goodrain/rainbond/test/ssl/client.pem",
CertKey: "/Users/qingguo/gopath/src/github.com/goodrain/rainbond/test/ssl/client.key.pem",
})
tenants, err := region.Tenants("").List()
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", tenants)
}

View File

@ -22,6 +22,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
@ -30,6 +31,7 @@ import (
"time"
"github.com/goodrain/rainbond/api/handler"
"github.com/goodrain/rainbond/api/webcli/app"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/version"
@ -42,9 +44,7 @@ import (
"github.com/goodrain/rainbond/api/api_routers/doc"
"github.com/goodrain/rainbond/api/api_routers/license"
"github.com/goodrain/rainbond/api/metric"
"github.com/goodrain/rainbond/api/proxy"
"github.com/goodrain/rainbond/api/api_routers/cloud"
"github.com/goodrain/rainbond/api/api_routers/version2"
"github.com/goodrain/rainbond/api/api_routers/websocket"
@ -62,20 +62,26 @@ type Manager struct {
conf option.Config
stopChan chan struct{}
r *chi.Mux
prometheusProxy proxy.Proxy
etcdcli *clientv3.Client
exporter *metric.Exporter
websocketModuls map[string]CustomModule
}
//CustomModule custom module set route for api
type CustomModule interface {
SetRoute(*chi.Mux) error
}
//NewManager newManager
func NewManager(c option.Config, etcdcli *clientv3.Client) *Manager {
func NewManager(c option.Config, etcdcli *clientv3.Client, webapp *app.App) *Manager {
ctx, cancel := context.WithCancel(context.Background())
manager := &Manager{
ctx: ctx,
cancel: cancel,
conf: c,
stopChan: make(chan struct{}),
etcdcli: etcdcli,
ctx: ctx,
cancel: cancel,
conf: c,
stopChan: make(chan struct{}),
etcdcli: etcdcli,
websocketModuls: map[string]CustomModule{"webapp": webapp},
}
r := chi.NewRouter()
manager.r = r
@ -144,7 +150,7 @@ func (m *Manager) Stop() error {
}
//Run run
func (m *Manager) Run() {
func (m *Manager) Run() error {
v2R := &version2.V2{
Cfg: &m.conf,
}
@ -156,22 +162,24 @@ func (m *Manager) Run() {
res.Write([]byte("ok"))
})
m.r.Mount("/v2", v2R.Routes())
m.r.Mount("/cloud", cloud.Routes())
m.r.Mount("/", doc.Routes())
m.r.Mount("/license", license.Routes())
//兼容老版docker
m.r.Get("/v1/etcd/event-log/instances", m.EventLogInstance)
m.r.Get("/kubernetes/dashboard", m.KuberntesDashboardAPI)
//prometheus单节点代理
m.r.Get("/api/v1/query", m.PrometheusAPI)
m.r.Get("/api/v1/query_range", m.PrometheusAPI)
//开启对浏览器的websocket服务和文件服务
//set websocket route
websocketRouter := chi.NewRouter()
websocketRouter.Mount("/", websocket.Routes())
websocketRouter.Mount("/logs", websocket.LogRoutes())
websocketRouter.Mount("/app", websocket.AppRoutes())
for _, c := range m.websocketModuls {
if err := c.SetRoute(websocketRouter); err != nil {
return fmt.Errorf("set websocket custom route failire %s", err.Error())
}
}
go func() {
websocketRouter := chi.NewRouter()
websocketRouter.Mount("/", websocket.Routes())
websocketRouter.Mount("/logs", websocket.LogRoutes())
websocketRouter.Mount("/app", websocket.AppRoutes())
if m.conf.WebsocketSSL {
logrus.Infof("websocket listen on (HTTPs) %s", m.conf.WebsocketAddr)
logrus.Fatal(http.ListenAndServeTLS(m.conf.WebsocketAddr, m.conf.WebsocketCertFile, m.conf.WebsocketKeyFile, websocketRouter))
@ -203,30 +211,7 @@ func (m *Manager) Run() {
}
logrus.Infof("api listen on (HTTP) %s", m.conf.APIAddr)
logrus.Fatal(http.ListenAndServe(m.conf.APIAddr, m.r))
}
//EventLogInstance 查询event server instance
func (m *Manager) EventLogInstance(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(m.ctx)
defer cancel()
res, err := m.etcdcli.Get(ctx, "/event/instance", clientv3.WithPrefix())
if err != nil {
w.WriteHeader(500)
return
}
if res.Kvs != nil && len(res.Kvs) > 0 {
result := `{"data":{"instance":[`
for _, kv := range res.Kvs {
result += string(kv.Value) + ","
}
result = result[:len(result)-1] + `]},"ok":true}`
w.Write([]byte(result))
w.WriteHeader(200)
return
}
w.WriteHeader(404)
return
return nil
}
//PrometheusAPI prometheus api 代理
@ -254,7 +239,7 @@ func (m *Manager) RequestMetric(next http.Handler) http.Handler {
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
defer func() {
path := r.RequestURI
if strings.Index(r.RequestURI, "?") > -1 {
if strings.Contains(r.RequestURI, "?") {
path = r.RequestURI[:strings.Index(r.RequestURI, "?")]
}
m.exporter.RequestInc(ww.Status(), path)

View File

@ -23,31 +23,26 @@ import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"strings"
"text/template"
"github.com/go-chi/chi"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/barnettZQG/gotty/server"
"github.com/barnettZQG/gotty/webtty"
httputil "github.com/goodrain/rainbond/util/http"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/gorilla/websocket"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/yudai/umutex"
api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
//ExecuteCommandTotal metric
@ -65,9 +60,9 @@ type App struct {
titleTemplate *template.Template
onceMutex *umutex.UnblockingMutex
restClient *restclient.RESTClient
restClient *rest.RESTClient
coreClient *kubernetes.Clientset
config *restclient.Config
config *rest.Config
}
//Options options
@ -92,11 +87,9 @@ var Version = "0.0.2"
//DefaultOptions -
var DefaultOptions = Options{
Address: "",
Port: "8080",
PermitWrite: true,
IndexFile: "",
TitleFormat: "GRTTY Command",
TitleFormat: "GRTTY Command For Component Instance",
EnableReconnect: true,
ReconnectTime: 10,
CloseSignal: 1, // syscall.SIGHUP
@ -137,63 +130,17 @@ func New(options *Options) (*App, error) {
return app, nil
}
//Run Run
func (app *App) Run() error {
endpoint := net.JoinHostPort(app.options.Address, app.options.Port)
wsHandler := http.HandlerFunc(app.handleWS)
health := http.HandlerFunc(app.healthCheck)
var siteMux = http.NewServeMux()
siteHandler := http.Handler(siteMux)
siteHandler = wrapHeaders(siteHandler)
exporter := NewExporter()
prometheus.MustRegister(exporter)
wsMux := http.NewServeMux()
wsMux.Handle("/", siteHandler)
wsMux.Handle("/docker_console", wsHandler)
wsMux.Handle("/health", health)
wsMux.Handle("/metrics", promhttp.Handler())
siteHandler = (http.Handler(wsMux))
siteHandler = wrapLogger(siteHandler)
server, err := app.makeServer(endpoint, &siteHandler)
if err != nil {
return errors.New("Failed to build server: " + err.Error())
}
go func() {
logrus.Printf("webcli listen %s", endpoint)
logrus.Fatal(server.ListenAndServe())
logrus.Printf("Exiting...")
}()
//SetRoute -
func (app *App) SetRoute(route *chi.Mux) error {
route.Handle("/docker_console", http.HandlerFunc(app.handleWS))
return nil
}
func (app *App) makeServer(addr string, handler *http.Handler) (*http.Server, error) {
server := &http.Server{
Addr: addr,
Handler: *handler,
}
return server, nil
}
func (app *App) healthCheck(w http.ResponseWriter, r *http.Request) {
httputil.ReturnSuccess(r, w, map[string]string{"status": "health", "info": "webcli service health"})
}
func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
logrus.Printf("New client connected: %s", r.RemoteAddr)
if r.Method != "GET" {
http.Error(w, "Method not allowed", 405)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
@ -215,7 +162,7 @@ func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
var init InitMessage
err = json.Unmarshal(stream, &init)
_ = json.Unmarshal(stream, &init)
//todo auth
if init.PodName == "" {
@ -278,11 +225,6 @@ func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
}
}
//Exit -
func (app *App) Exit() (firstCall bool) {
return true
}
func (app *App) createKubeClient() error {
config, err := k8sutil.NewRestConfig(app.options.K8SConfPath)
if err != nil {
@ -295,7 +237,7 @@ func (app *App) createKubeClient() error {
}
SetConfigDefaults(config)
app.config = config
restClient, err := restclient.RESTClientFor(config)
restClient, err := rest.RESTClientFor(config)
if err != nil {
return err
}
@ -342,7 +284,7 @@ func (app *App) GetContainerArgs(namespace, podname, containerName string) (stri
}
//NewRequest new exec request
func (app *App) NewRequest(podName, namespace, containerName string, command []string) *restclient.Request {
func (app *App) NewRequest(podName, namespace, containerName string, command []string) *rest.Request {
// TODO: consider abstracting into a client invocation or client helper
req := app.restClient.Post().
Resource("pods").
@ -360,21 +302,6 @@ func (app *App) NewRequest(podName, namespace, containerName string, command []s
return req
}
func wrapLogger(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rw := &responseWrapper{w, 200}
handler.ServeHTTP(rw, r)
logrus.Printf("%s %d %s %s", r.RemoteAddr, rw.status, r.Method, r.URL.Path)
})
}
func wrapHeaders(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", "GoTTY/"+Version)
handler.ServeHTTP(w, r)
})
}
func md5Func(str string) string {
h := md5.New()
h.Write([]byte(str))

View File

@ -7,7 +7,7 @@ import (
// Metric name parts.
const (
// Namespace for all metrics.
namespace = "webcli"
namespace = "api"
// Subsystem(s).
exporter = "exporter"
)

View File

@ -22,7 +22,7 @@ import (
"io"
"os"
"github.com/goodrain/rainbond/webcli/term"
"github.com/goodrain/rainbond/api/webcli/term"
"github.com/sirupsen/logrus"
)

View File

@ -16,10 +16,9 @@ import (
jobc "github.com/goodrain/rainbond/builder/job"
"github.com/goodrain/rainbond/builder/parser/code"
"github.com/goodrain/rainbond/builder/sources"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/event"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"k8s.io/client-go/kubernetes"
@ -36,7 +35,6 @@ func TestCreateJob(t *testing.T) {
}
event.NewManager(event.EventConfig{
EventLogServers: conf.EventLogServers,
DiscoverArgs: &etcdutil.ClientArgs{Endpoints: conf.EtcdEndPoints},
})
restConfig, err := k8sutil.NewRestConfig("/Users/fanyangyang/Documents/company/goodrain/remote/192.168.2.206/admin.kubeconfig")
if err != nil {

View File

@ -26,7 +26,7 @@ import (
"time"
"github.com/goodrain/rainbond/builder/exector"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
"github.com/goodrain/rainbond/mq/client"
"github.com/sirupsen/logrus"

View File

@ -35,7 +35,7 @@ import (
"github.com/tidwall/gjson"
"github.com/goodrain/rainbond/builder/job"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/db"
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/mq/api/grpc/pb"

View File

@ -30,12 +30,11 @@ import (
"k8s.io/client-go/kubernetes"
"github.com/goodrain/rainbond/builder/parser/code"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
mqclient "github.com/goodrain/rainbond/mq/client"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
)
@ -48,10 +47,8 @@ func Test_exectorManager_buildFromSourceCode(t *testing.T) {
RbdNamespace: "rbd-system",
MysqlConnectionInfo: "EeM2oc:lee7OhQu@tcp(192.168.2.203:3306)/region",
}
etcdArgs := etcdutil.ClientArgs{Endpoints: conf.EtcdEndPoints}
event.NewManager(event.EventConfig{
EventLogServers: conf.EventLogServers,
DiscoverArgs: &etcdArgs,
})
restConfig, err := k8sutil.NewRestConfig("/Users/fanyangyang/Documents/company/goodrain/admin.kubeconfig")
if err != nil {
@ -72,7 +69,7 @@ func Test_exectorManager_buildFromSourceCode(t *testing.T) {
} else {
maxConcurrentTask = conf.MaxTasks
}
mqClient, err := mqclient.NewMqClient(&etcdArgs, conf.MQAPI)
mqClient, err := mqclient.NewMqClient(conf.MQAPI)
if err != nil {
t.Fatal(err)
}

View File

@ -22,7 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
eventutil "github.com/goodrain/rainbond/eventlog/util"
"github.com/pquerna/ffjson/ffjson"
"github.com/sirupsen/logrus"

View File

@ -1,54 +0,0 @@
// 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 discovery
import (
"strings"
)
// Discoverier blablabla
type Discoverier interface {
Connect() error
Fetch() ([]*Endpoint, error)
Close() error
}
// NewDiscoverier creates a new Discoverier
func NewDiscoverier(info *Info) Discoverier {
switch strings.ToUpper(info.Type) {
case "ETCD":
return NewEtcd(info)
}
return nil
}
// Info holds service discovery center information.
type Info struct {
Type string `json:"type"`
Servers []string `json:"servers"`
Key string `json:"key"`
Username string `json:"username"`
Password string `json:"password"`
}
// Endpoint holds endpoint and endpoint status(online or offline).
type Endpoint struct {
Ep string `json:"endpoint"`
IsOnline bool `json:"is_online"`
}

View File

@ -1,103 +0,0 @@
// 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 discovery
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
c "github.com/coreos/etcd/clientv3"
"github.com/sirupsen/logrus"
)
// Etcd implements Discoverier
type etcd struct {
cli *c.Client
endpoints []string
key string
username string
password string
}
// NewEtcd creates a new Discorvery which implemeted by etcd.
func NewEtcd(info *Info) Discoverier {
// TODO: validate endpoints
return &etcd{
endpoints: info.Servers,
key: info.Key,
username: info.Username,
password: info.Password,
}
}
// Connect connects a etcdv3 client with a given configuration.
func (e *etcd) Connect() error {
cli, err := c.New(c.Config{
Endpoints: e.endpoints,
DialTimeout: 10 * time.Second,
Username: e.username,
Password: e.password,
})
if err != nil {
logrus.Errorf("Endpoints: %s; error connecting etcd: %v", strings.Join(e.endpoints, ","), err)
return err
}
e.cli = cli
return nil
}
// Fetch fetches data from Etcd.
func (e *etcd) Fetch() ([]*Endpoint, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if e.cli == nil {
return nil, fmt.Errorf("can't fetching data from etcd without etcdv3 client")
}
resp, err := e.cli.Get(ctx, e.key, c.WithPrefix())
if err != nil {
return nil, fmt.Errorf("error fetching endpoints form etcd: %v", err)
}
if resp == nil {
return nil, fmt.Errorf("error fetching endpoints form etcd: empty GetResponse")
}
var res []*Endpoint
for _, kv := range resp.Kvs {
var ep Endpoint
if err := json.Unmarshal(kv.Value, &ep); err != nil {
return nil, fmt.Errorf("error parsing the data from etcd: %v", err)
}
ep.Ep = strings.Replace(string(kv.Key), e.key+"/", "", -1)
res = append(res, &ep)
}
return res, nil
}
// Close shuts down the client's etcd connections.
func (e *etcd) Close() error {
if e.cli != nil {
return nil
}
return e.cli.Close()
}

View File

@ -1,19 +0,0 @@
// 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 discovery

View File

@ -26,7 +26,6 @@ import (
"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"
"github.com/sirupsen/logrus"
@ -184,8 +183,6 @@ type ServiceInfo struct {
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

View File

@ -19,22 +19,16 @@
package parser
import (
"encoding/json"
"strings"
"github.com/goodrain/rainbond/builder/parser/discovery"
"github.com/goodrain/rainbond/event"
"github.com/sirupsen/logrus"
)
// ThirdPartyServiceParse is one of the implematation of parser.Parser
type ThirdPartyServiceParse struct {
sourceBody string
endpoints []*discovery.Endpoint
errors []ParseError
logger event.Logger
errors []ParseError
logger event.Logger
}
// CreateThirdPartyServiceParse creates a new ThirdPartyServiceParse.
@ -53,41 +47,13 @@ func (t *ThirdPartyServiceParse) Parse() ParseErrorList {
return nil
}
var info discovery.Info
if err := json.Unmarshal([]byte(t.sourceBody), &info); err != nil {
logrus.Errorf("wrong source_body: %v, source_body: %s", err, t.sourceBody)
t.logger.Error("第三方检查输入参数错误", map[string]string{"step": "parse"})
t.errors = append(t.errors, ParseError{FatalError, "wrong input data", ""})
return t.errors
}
// TODO: validate data
d := discovery.NewDiscoverier(&info)
err := d.Connect()
if err != nil {
t.logger.Error("error connecting discovery center", map[string]string{"step": "parse"})
t.errors = append(t.errors, ParseError{FatalError, "error connecting discovery center", "please make sure " +
"the configuration is right and the discovery center is working."})
return t.errors
}
defer d.Close()
eps, err := d.Fetch()
if err != nil {
t.logger.Error("error fetching endpints", map[string]string{"step": "parse"})
t.errors = append(t.errors, ParseError{FatalError, "error fetching endpints", "please check the given key."})
return t.errors
}
t.endpoints = eps
return nil
}
// GetServiceInfo returns information of third-party service from
// the receiver *ThirdPartyServiceParse.
func (t *ThirdPartyServiceParse) GetServiceInfo() []ServiceInfo {
serviceInfo := ServiceInfo{
Endpoints: t.endpoints,
}
serviceInfo := ServiceInfo{}
return []ServiceInfo{serviceInfo}
}

View File

@ -1,5 +1,8 @@
#!/bin/sh
pull_number=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
#!/bin/bash
if [ -z $pull_number ]; then
pull_number=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
fi
URL="https://api.github.com/repos/goodrain/rainbond/pulls/${pull_number}/files"
@ -11,4 +14,4 @@ for file in ${CHANGED_MARKDOWN_FILES}; do
golint -set_exit_status=true ${file} || exit 1
done
echo "code golint check success"
echo "code golint check success"

View File

@ -32,9 +32,7 @@ type Config struct {
APIAddrSSL string
DBConnectionInfo string
EventLogServers []string
NodeAPI []string
BuilderAPI []string
V1API string
MQAPI string
EtcdEndpoint []string
EtcdCaFile string
@ -48,20 +46,17 @@ type Config struct {
WebsocketCertFile string
WebsocketKeyFile string
WebsocketAddr string
Opentsdb string
RegionTag string
LoggerFile string
EnableFeature []string
Debug bool
MinExtPort int // minimum external port
LicensePath string
LicSoPath string
LogPath string
KuberentesDashboardAPI string
KubeConfigPath string
PrometheusEndpoint string
RbdNamespace string
ShowSQL bool
WorkerAddress string
}
//APIServer apiserver server
@ -91,29 +86,24 @@ func (a *APIServer) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&a.WebsocketSSL, "ws-ssl-enable", false, "whether to enable websocket SSL")
fs.StringVar(&a.WebsocketCertFile, "ws-ssl-certfile", "/etc/ssl/goodrain.com/goodrain.com.crt", "websocket and fileserver ssl cert file")
fs.StringVar(&a.WebsocketKeyFile, "ws-ssl-keyfile", "/etc/ssl/goodrain.com/goodrain.com.key", "websocket and fileserver ssl key file")
fs.StringVar(&a.V1API, "v1-api", "127.0.0.1:8887", "the region v1 api")
fs.StringSliceVar(&a.NodeAPI, "node-api", []string{"127.0.0.1:6100"}, "the node server api")
fs.StringSliceVar(&a.BuilderAPI, "builder-api", []string{"rbd-chaos:3228"}, "the builder api")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"127.0.0.1:6366"}, "event log server address. simple lb")
fs.StringVar(&a.MQAPI, "mq-api", "127.0.0.1:6300", "acp_mq api")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"rbd-eventlog:6366"}, "event log server address.")
fs.StringVar(&a.MQAPI, "mq-api", "rbd-mq:6300", "acp_mq api")
fs.BoolVar(&a.StartRegionAPI, "start", false, "Whether to start region old api")
fs.StringSliceVar(&a.EtcdEndpoint, "etcd", []string{"http://127.0.0.1:2379"}, "etcd server or proxy address")
fs.StringVar(&a.EtcdCaFile, "etcd-ca", "", "verify etcd certificates of TLS-enabled secure servers using this CA bundle")
fs.StringVar(&a.EtcdCertFile, "etcd-cert", "", "identify secure etcd client using this TLS certificate file")
fs.StringVar(&a.EtcdKeyFile, "etcd-key", "", "identify secure etcd client using this TLS key file")
fs.StringVar(&a.Opentsdb, "opentsdb", "127.0.0.1:4242", "opentsdb server config")
fs.StringVar(&a.RegionTag, "region-tag", "test-ali", "region tag setting")
fs.StringVar(&a.LoggerFile, "logger-file", "/logs/request.log", "request log file path")
fs.BoolVar(&a.Debug, "debug", false, "open debug will enable pprof")
fs.IntVar(&a.MinExtPort, "min-ext-port", 0, "minimum external port")
fs.StringArrayVar(&a.EnableFeature, "enable-feature", []string{}, "List of special features supported, such as `windows`")
fs.StringVar(&a.LicensePath, "license-path", "/opt/rainbond/etc/license/license.yb", "the license path of the enterprise version.")
fs.StringVar(&a.LicSoPath, "license-so-path", "/opt/rainbond/etc/license/license.so", "Dynamic library file path for parsing the license.")
fs.StringVar(&a.LogPath, "log-path", "/grdata/logs", "Where Docker log files and event log files are stored.")
fs.StringVar(&a.KubeConfigPath, "kube-config", "", "kube config file path, No setup is required to run in a cluster.")
fs.StringVar(&a.KuberentesDashboardAPI, "k8s-dashboard-api", "kubernetes-dashboard.rbd-system:443", "The service DNS name of Kubernetes dashboard. Default to kubernetes-dashboard.kubernetes-dashboard")
fs.StringVar(&a.PrometheusEndpoint, "prom-api", "rbd-monitor:9999", "The service DNS name of Prometheus api. Default to rbd-monitor:9999")
fs.StringVar(&a.RbdNamespace, "rbd-namespace", "rbd-system", "rbd component namespace")
fs.StringVar(&a.WorkerAddress, "worker-address", "rbd-worker:6535", "the address of worker runtime server")
fs.BoolVar(&a.ShowSQL, "show-sql", false, "The trigger for showing sql.")
}

View File

@ -23,17 +23,16 @@ import (
"os"
"os/signal"
"syscall"
rainbondscheme "github.com/goodrain/rainbond/pkg/generated/clientset/versioned/scheme"
"github.com/goodrain/rainbond/api/controller"
"github.com/goodrain/rainbond/api/db"
"github.com/goodrain/rainbond/api/discover"
"github.com/goodrain/rainbond/api/handler"
"github.com/goodrain/rainbond/api/server"
"github.com/goodrain/rainbond/api/webcli/app"
"github.com/goodrain/rainbond/cmd/api/option"
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
rainbondscheme "github.com/goodrain/rainbond/pkg/generated/clientset/versioned/scheme"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/goodrain/rainbond/worker/client"
@ -57,10 +56,6 @@ func Run(s *option.APIServer) error {
CertFile: s.Config.EtcdCertFile,
KeyFile: s.Config.EtcdKeyFile,
}
//启动服务发现
if _, err := discover.CreateEndpointDiscover(etcdClientArgs); err != nil {
return err
}
//创建db manager
if err := db.CreateDBManager(s.Config); err != nil {
logrus.Debugf("create db manager error, %v", err)
@ -94,18 +89,14 @@ func Run(s *option.APIServer) error {
if err := event.NewManager(event.EventConfig{
EventLogServers: s.Config.EventLogServers,
DiscoverArgs: etcdClientArgs,
}); err != nil {
return err
}
defer event.CloseManager()
//create app status client
cli, err := client.NewClient(ctx, client.AppRuntimeSyncClientConf{
EtcdEndpoints: s.Config.EtcdEndpoint,
EtcdCaFile: s.Config.EtcdCaFile,
EtcdCertFile: s.Config.EtcdCertFile,
EtcdKeyFile: s.Config.EtcdKeyFile,
NonBlock: s.Config.Debug,
DefaultServerAddress: s.Config.WorkerAddress,
NonBlock: s.Config.Debug,
})
if err != nil {
logrus.Errorf("create app status client error, %v", err)
@ -118,19 +109,30 @@ func Run(s *option.APIServer) error {
return err
}
//初始化 middleware
//init middleware
handler.InitProxy(s.Config)
//创建handle
//create handle
if err := handler.InitHandle(s.Config, etcdClientArgs, cli, etcdcli, clientset, rainbondClient, k8sClient); err != nil {
logrus.Errorf("init all handle error, %v", err)
return err
}
//创建v2Router manager
// webcli modul
option := app.DefaultOptions
option.K8SConfPath = s.Config.KubeConfigPath
cliapp, err := app.New(&option)
if err != nil {
logrus.Errorf("new webcli app failure %v", err)
return err
}
// create v2Router manager
if err := controller.CreateV2RouterManager(s.Config, cli); err != nil {
logrus.Errorf("create v2 route manager error, %v", err)
}
// 启动api
apiManager := server.NewManager(s.Config, etcdcli)
// start server listen
apiManager := server.NewManager(s.Config, etcdcli, cliapp)
if err := apiManager.Start(); err != nil {
return err
}
@ -138,7 +140,7 @@ func Run(s *option.APIServer) error {
logrus.Info("api router is running...")
//step finally: listen Signal
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case s := <-term:

View File

@ -23,8 +23,8 @@ import (
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/builder/server"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/cmd/chaos/server"
"github.com/spf13/pflag"
)

View File

@ -81,11 +81,11 @@ func (a *Builder) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&a.PrometheusMetricPath, "metric", "/metrics", "prometheus metrics path")
fs.StringVar(&a.DBType, "db-type", "mysql", "db type mysql or etcd")
fs.StringVar(&a.MysqlConnectionInfo, "mysql", "root:admin@tcp(127.0.0.1:3306)/region", "mysql db connection info")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"127.0.0.1:6366"}, "event log server address. simple lb")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"rbd-eventlog:6366"}, "event log server address. simple lb")
fs.StringVar(&a.KubeConfig, "kube-config", "", "kubernetes api server config file")
fs.IntVar(&a.MaxTasks, "max-tasks", 50, "Maximum number of simultaneous build tasks")
fs.IntVar(&a.APIPort, "api-port", 3228, "the port for api server")
fs.StringVar(&a.MQAPI, "mq-api", "127.0.0.1:6300", "acp_mq api")
fs.StringVar(&a.MQAPI, "mq-api", "rbd-mq:6300", "acp_mq api")
fs.StringVar(&a.RunMode, "run", "sync", "sync data when worker start")
fs.StringVar(&a.DockerEndpoint, "dockerd", "127.0.0.1:2376", "dockerd endpoint")
fs.StringVar(&a.HostIP, "hostIP", "", "Current node Intranet IP")

View File

@ -26,7 +26,7 @@ import (
"github.com/goodrain/rainbond/builder/discover"
"github.com/goodrain/rainbond/builder/exector"
"github.com/goodrain/rainbond/builder/monitor"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/chaos/option"
"github.com/goodrain/rainbond/db"
"github.com/goodrain/rainbond/db/config"
"github.com/goodrain/rainbond/event"
@ -36,8 +36,6 @@ import (
"github.com/goodrain/rainbond/builder/api"
"github.com/goodrain/rainbond/builder/clean"
discoverv2 "github.com/goodrain/rainbond/discover.v2"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
@ -50,26 +48,17 @@ func Run(s *option.Builder) error {
dbconfig := config.Config{
DBType: s.Config.DBType,
MysqlConnectionInfo: s.Config.MysqlConnectionInfo,
EtcdEndPoints: s.Config.EtcdEndPoints,
EtcdTimeout: s.Config.EtcdTimeout,
}
if err := db.CreateManager(dbconfig); err != nil {
return err
}
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: s.Config.EtcdEndPoints,
CaFile: s.Config.EtcdCaFile,
CertFile: s.Config.EtcdCertFile,
KeyFile: s.Config.EtcdKeyFile,
}
if err := event.NewManager(event.EventConfig{
EventLogServers: s.Config.EventLogServers,
DiscoverArgs: etcdClientArgs,
}); err != nil {
return err
}
defer event.CloseManager()
client, err := client.NewMqClient(etcdClientArgs, s.Config.MQAPI)
client, err := client.NewMqClient(s.Config.MQAPI)
if err != nil {
logrus.Errorf("new Mq client error, %v", err)
return err
@ -98,15 +87,6 @@ func Run(s *option.Builder) error {
}
defer cle.Stop()
}
keepalive, err := discoverv2.CreateKeepAlive(etcdClientArgs, "builder",
"", s.Config.HostIP, s.Config.APIPort)
if err != nil {
return err
}
if err := keepalive.Start(); err != nil {
return err
}
defer keepalive.Stop()
exporter := monitor.NewExporter(exec)
prometheus.MustRegister(exporter)
@ -117,7 +97,7 @@ func Run(s *option.Builder) error {
logrus.Info("builder begin running...")
//step finally: listen Signal
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-term:

View File

@ -27,16 +27,16 @@ import (
"syscall"
"time"
"github.com/goodrain/rainbond/discover"
"github.com/goodrain/rainbond/eventlog/cluster"
"github.com/goodrain/rainbond/eventlog/conf"
"github.com/goodrain/rainbond/eventlog/db"
"github.com/goodrain/rainbond/eventlog/entry"
"github.com/goodrain/rainbond/eventlog/exit/web"
"github.com/goodrain/rainbond/eventlog/store"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"k8s.io/client-go/kubernetes"
)
// LogServer -
@ -69,17 +69,10 @@ func (s *LogServer) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&s.Conf.Entry.MonitorMessageServer.CacheMessageSize, "monitor.cache", 200, "the monitor sub server cache the receive message size")
fs.StringVar(&s.Conf.Entry.MonitorMessageServer.SubSubscribe, "monitor.subscribe", "ceptop", "the monitor message sub server subscribe info")
fs.BoolVar(&s.Conf.ClusterMode, "cluster", true, "Whether open cluster mode")
fs.StringVar(&s.Conf.Cluster.Discover.InstanceIP, "cluster.instance.ip", "", "The current instance IP in the cluster can be communications.")
fs.StringVar(&s.Conf.Cluster.Discover.Type, "discover.type", "etcd", "the instance in cluster auto discover way.")
fs.StringSliceVar(&s.Conf.Cluster.Discover.EtcdAddr, "discover.etcd.addr", []string{"http://127.0.0.1:2379"}, "set all etcd server addr in cluster for message instence auto discover.")
fs.StringVar(&s.Conf.Cluster.Discover.EtcdCaFile, "discover.etcd.ca", "", "verify etcd certificates of TLS-enabled secure servers using this CA bundle")
fs.StringVar(&s.Conf.Cluster.Discover.EtcdCertFile, "discover.etcd.cert", "", "identify secure etcd client using this TLS certificate file")
fs.StringVar(&s.Conf.Cluster.Discover.EtcdKeyFile, "discover.etcd.key", "", "identify secure etcd client using this TLS key file")
fs.StringVar(&s.Conf.Cluster.Discover.HomePath, "discover.etcd.homepath", "/event", "etcd home key")
fs.StringVar(&s.Conf.Cluster.Discover.EtcdUser, "discover.etcd.user", "", "etcd server user info")
fs.StringVar(&s.Conf.Cluster.Discover.EtcdPass, "discover.etcd.pass", "", "etcd server user password")
fs.StringVar(&s.Conf.Cluster.HostIP, "cluster.instance.ip", "", "The current instance IP in the cluster can be communications.")
fs.StringVar(&s.Conf.Cluster.PubSub.PubBindIP, "cluster.bind.ip", "0.0.0.0", "Cluster communication to listen the IP")
fs.IntVar(&s.Conf.Cluster.PubSub.PubBindPort, "cluster.bind.port", 6365, "Cluster communication to listen the Port")
fs.IntVar(&s.Conf.Cluster.ClusterPort, "cluster.leader.port", 6367, "leader server bind port")
fs.StringVar(&s.Conf.EventStore.MessageType, "message.type", "json", "Receive and transmit the log message type.")
fs.StringVar(&s.Conf.EventStore.GarbageMessageSaveType, "message.garbage.save", "file", "garbage message way of storage")
fs.StringVar(&s.Conf.EventStore.GarbageMessageFile, "message.garbage.file", "/var/log/envent_garbage_message.log", "save garbage message file path when save type is file")
@ -111,8 +104,9 @@ func (s *LogServer) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.Conf.EventStore.DB.HomePath, "docker.log.homepath", "/grdata/logs/", "container log persistent home path")
fs.StringVar(&s.Conf.Entry.NewMonitorMessageServerConf.ListenerHost, "monitor.udp.host", "0.0.0.0", "receive new monitor udp server host")
fs.IntVar(&s.Conf.Entry.NewMonitorMessageServerConf.ListenerPort, "monitor.udp.port", 6166, "receive new monitor udp server port")
fs.StringVar(&s.Conf.Cluster.Discover.NodeID, "node-id", "", "the unique ID for this node.")
fs.DurationVar(&s.Conf.Cluster.PubSub.PollingTimeout, "zmq4-polling-timeout", 200*time.Millisecond, "The timeout determines the time-out on the polling of sockets")
fs.StringVar(&s.Conf.KubeConfigPath, "kubeconfig", "", "path to kubeconfig file with authorization and master location information.")
fs.StringVar(&s.Conf.Cluster.LeaderElectionNamespace, "leader-election-namespace", "rbd-system", "Namespace where this attacher runs.")
}
//InitLog 初始化log
@ -157,11 +151,9 @@ func (s *LogServer) InitLog() {
//InitConf 初始化配置
func (s *LogServer) InitConf() {
s.Conf.Cluster.Discover.ClusterMode = s.Conf.ClusterMode
s.Conf.Cluster.PubSub.ClusterMode = s.Conf.ClusterMode
s.Conf.EventStore.ClusterMode = s.Conf.ClusterMode
s.Conf.Cluster.Discover.DockerLogPort = s.Conf.Entry.DockerLogServer.BindPort
s.Conf.Cluster.Discover.WebPort = s.Conf.WebSocket.BindPort
s.Conf.Cluster.DockerLogPort = s.Conf.Entry.DockerLogServer.BindPort
s.Conf.Cluster.WebsocketPort = s.Conf.WebSocket.BindPort
if os.Getenv("MYSQL_HOST") != "" && os.Getenv("MYSQL_USER") != "" && os.Getenv("MYSQL_PASSWORD") != "" {
s.Conf.EventStore.DB.URL = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", os.Getenv("MYSQL_USER"), os.Getenv("MYSQL_PASSWORD"),
os.Getenv("MYSQL_HOST"), os.Getenv("MYSQL_PORT"), os.Getenv("MYSQL_DATABASE"))
@ -176,27 +168,23 @@ func (s *LogServer) Run() error {
s.Logger.Debug("Start run server.")
log := s.Logger
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: s.Conf.Cluster.Discover.EtcdAddr,
CaFile: s.Conf.Cluster.Discover.EtcdCaFile,
CertFile: s.Conf.Cluster.Discover.EtcdCertFile,
KeyFile: s.Conf.Cluster.Discover.EtcdKeyFile,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
etcdClient, err := etcdutil.NewClient(ctx, etcdClientArgs)
if err != nil {
return err
}
//init new db
if err := db.CreateDBManager(s.Conf.EventStore.DB); err != nil {
logrus.Infof("create db manager error, %v", err)
return err
}
config, err := k8sutil.NewRestConfig(s.Conf.KubeConfigPath)
if err != nil {
return err
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return err
}
storeManager, err := store.NewManager(s.Conf.EventStore, log.WithField("module", "MessageStore"))
if err != nil {
return err
@ -206,15 +194,12 @@ func (s *LogServer) Run() error {
return err
}
defer storeManager.Stop()
if s.Conf.ClusterMode {
s.Cluster = cluster.NewCluster(etcdClient, s.Conf.Cluster, log.WithField("module", "Cluster"), storeManager)
if err := s.Cluster.Start(); err != nil {
return err
}
defer s.Cluster.Stop()
s.Cluster = cluster.NewCluster(ctx, s.Conf.Cluster, clientset, log.WithField("module", "Cluster"), storeManager)
if err := s.Cluster.Start(); err != nil {
return err
}
s.SocketServer = web.NewSocket(s.Conf.WebSocket, s.Conf.Cluster.Discover, etcdClient,
log.WithField("module", "SocketServer"), storeManager, s.Cluster, healthInfo)
defer s.Cluster.Stop()
s.SocketServer = web.NewSocket(s.Conf.WebSocket, log.WithField("module", "SocketServer"), storeManager, s.Cluster, healthInfo)
if err := s.SocketServer.Run(); err != nil {
return err
}
@ -226,38 +211,7 @@ func (s *LogServer) Run() error {
}
defer s.Entry.Stop()
//服务注册
grpckeepalive, err := discover.CreateKeepAlive(etcdClientArgs, "event_log_event_grpc",
s.Conf.Cluster.Discover.NodeID, s.Conf.Cluster.Discover.InstanceIP, s.Conf.Entry.EventLogServer.BindPort)
if err != nil {
return err
}
if err := grpckeepalive.Start(); err != nil {
return err
}
defer grpckeepalive.Stop()
udpkeepalive, err := discover.CreateKeepAlive(etcdClientArgs, "event_log_event_udp",
s.Conf.Cluster.Discover.NodeID, s.Conf.Cluster.Discover.InstanceIP, s.Conf.Entry.NewMonitorMessageServerConf.ListenerPort)
if err != nil {
return err
}
if err := udpkeepalive.Start(); err != nil {
return err
}
defer udpkeepalive.Stop()
httpkeepalive, err := discover.CreateKeepAlive(etcdClientArgs, "event_log_event_http",
s.Conf.Cluster.Discover.NodeID, s.Conf.Cluster.Discover.InstanceIP, s.Conf.WebSocket.BindPort)
if err != nil {
return err
}
if err := httpkeepalive.Start(); err != nil {
return err
}
defer httpkeepalive.Stop()
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-term:

View File

@ -36,7 +36,6 @@ import (
"k8s.io/client-go/kubernetes"
"github.com/goodrain/rainbond/cmd/gateway/option"
"github.com/goodrain/rainbond/discover"
"github.com/goodrain/rainbond/gateway/cluster"
"github.com/goodrain/rainbond/gateway/controller"
"github.com/goodrain/rainbond/gateway/metric"
@ -118,17 +117,6 @@ func Run(s *option.GWServer) error {
}
go startHTTPServer(s.ListenPorts.Health, mux)
keepalive, err := discover.CreateKeepAlive(etcdClientArgs, "gateway", s.Config.NodeName,
s.Config.HostIP, s.ListenPorts.Health)
if err != nil {
return err
}
logrus.Debug("start keepalive")
if err := keepalive.Start(); err != nil {
return err
}
defer keepalive.Stop()
logrus.Info("RBD app gateway start success!")
term := make(chan os.Signal)

View File

@ -19,21 +19,14 @@
package main
import (
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/monitor/custom"
"github.com/goodrain/rainbond/cmd/monitor/option"
"github.com/goodrain/rainbond/monitor"
"github.com/goodrain/rainbond/monitor/api"
"github.com/goodrain/rainbond/monitor/api/controller"
"github.com/goodrain/rainbond/monitor/prometheus"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
@ -51,33 +44,23 @@ func main() {
c.CompleteConfig()
// start prometheus daemon and watching tis status in all time, exit monitor process if start failed
a := prometheus.NewRulesManager(c)
p := prometheus.NewManager(c, a)
controllerManager := controller.NewControllerManager(a, p)
p := prometheus.NewManager(c)
monitorMysql(c, p)
monitorKSM(c, p)
// start watching prometheus config from kube api, and update modify to prometheus config
m, err := monitor.NewMonitor(c, p)
if err != nil {
logrus.Fatalf("new monitor module failure %s", err.Error())
}
m.Start()
defer m.Stop()
errChan := make(chan error, 1)
defer close(errChan)
p.StartDaemon(errChan)
defer p.StopDaemon()
// register prometheus address to etcd cluster
p.Registry.Start()
defer p.Registry.Stop()
// start watching components from etcd, and update modify to prometheus config
m := monitor.NewMonitor(c, p)
m.Start()
defer m.Stop()
r := api.Server(controllerManager)
logrus.Info("monitor api listen port 3329")
go http.ListenAndServe(":3329", r)
//step finally: listen Signal
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
defer close(term)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
@ -91,29 +74,3 @@ func main() {
}
logrus.Info("See you next time!")
}
func monitorMysql(c *option.Config, p *prometheus.Manager) {
if strings.TrimSpace(c.MysqldExporter) != "" {
metrics := strings.TrimSpace(c.MysqldExporter)
logrus.Infof("add mysql metrics[%s] into prometheus", metrics)
custom.AddMetrics(p, custom.Metrics{Name: "mysql", Path: "/metrics", Metrics: []string{metrics}, Interval: 30 * time.Second, Timeout: 15 * time.Second})
}
}
func monitorKSM(c *option.Config, p *prometheus.Manager) {
if strings.TrimSpace(c.KSMExporter) != "" {
metrics := strings.TrimSpace(c.KSMExporter)
logrus.Infof("add kube-state-metrics[%s] into prometheus", metrics)
custom.AddMetrics(p, custom.Metrics{
Name: "kubernetes",
Path: "/metrics",
Scheme: func() string {
if strings.HasSuffix(metrics, "443") {
return "https"
}
return "http"
}(),
Metrics: []string{metrics}, Interval: 30 * time.Second, Timeout: 10 * time.Second},
)
}
}

View File

@ -21,7 +21,6 @@ package option
import (
"fmt"
"os"
"strconv"
"strings"
"time"
@ -31,18 +30,13 @@ import (
// Config config
type Config struct {
EtcdEndpointsLine string
EtcdEndpoints []string
EtcdCaFile string
EtcdCertFile string
EtcdKeyFile string
LogLevel string
AdvertiseAddr string
BindIP string
Port int
MetricPort int
StartArgs []string
ConfigFile string
AlertingRulesFile string
AlertingRulesFileDir string
AlertManagerURL []string
LocalStoragePath string
Web Web
@ -54,9 +48,6 @@ type Config struct {
QueryLookbackDelta string
QueryTimeout string
QueryMaxConcurrency string
CadvisorListenPort int
MysqldExporter string
KSMExporter string
KubeConfig string
}
@ -99,15 +90,13 @@ func NewConfig() *Config {
host, _ := os.Hostname()
config := &Config{
EtcdEndpointsLine: "http://127.0.0.1:2379",
EtcdEndpoints: []string{},
AdvertiseAddr: host + ":9999",
BindIP: host,
Port: 9999,
MetricPort: 3329,
LogLevel: "info",
KubeConfig: "",
ConfigFile: "/etc/prometheus/prometheus.yml",
AlertingRulesFile: "/etc/prometheus/rules.yml",
AlertingRulesFileDir: "/etc/prometheus/rules",
AlertManagerURL: []string{},
LocalStoragePath: "/prometheusdata",
WebTimeout: "5m",
@ -128,7 +117,6 @@ func NewConfig() *Config {
MinBlockDuration: "2h",
Retention: "7d",
},
CadvisorListenPort: 10250,
}
return config
@ -136,15 +124,7 @@ func NewConfig() *Config {
//AddFlag monitor flag
func (c *Config) AddFlag(cmd *pflag.FlagSet) {
cmd.StringVar(&c.EtcdEndpointsLine, "etcd-endpoints", c.EtcdEndpointsLine, "etcd endpoints list.")
cmd.StringVar(&c.EtcdCaFile, "etcd-ca", "", "etcd tls ca file ")
cmd.StringVar(&c.EtcdCertFile, "etcd-cert", "", "etcd tls cert file")
cmd.StringVar(&c.EtcdKeyFile, "etcd-key", "", "etcd http tls cert key file")
cmd.StringVar(&c.AdvertiseAddr, "advertise-addr", c.AdvertiseAddr, "advertise address, and registry into etcd.")
cmd.IntVar(&c.CadvisorListenPort, "cadvisor-listen-port", c.CadvisorListenPort, "kubelet cadvisor listen port in all node")
cmd.StringSliceVar(&c.AlertManagerURL, "alertmanager-address", c.AlertManagerURL, "AlertManager url.")
cmd.StringVar(&c.MysqldExporter, "mysqld-exporter", c.MysqldExporter, "mysqld exporter address. eg: 127.0.0.1:9104")
cmd.StringVar(&c.KSMExporter, "kube-state-metrics", c.KSMExporter, "kube-state-metrics, current server's kube-state-metrics address")
cmd.StringVar(&c.KubeConfig, "kube-config", "", "kubernetes api server config file")
}
@ -152,7 +132,7 @@ func (c *Config) AddFlag(cmd *pflag.FlagSet) {
func (c *Config) AddPrometheusFlag(cmd *pflag.FlagSet) {
cmd.StringVar(&c.ConfigFile, "config.file", c.ConfigFile, "Prometheus configuration file path.")
cmd.StringVar(&c.AlertingRulesFile, "rules-config.file", c.AlertingRulesFile, "Prometheus alerting rules config file path.")
cmd.StringVar(&c.AlertingRulesFileDir, "rules-config.dir", c.AlertingRulesFileDir, "Prometheus alerting rules config file path.")
cmd.StringVar(&c.Web.ListenAddress, "web.listen-address", c.Web.ListenAddress, "Address to listen on for UI, API, and telemetry.")
@ -202,25 +182,6 @@ func (c *Config) AddPrometheusFlag(cmd *pflag.FlagSet) {
// CompleteConfig complete config
func (c *Config) CompleteConfig() {
// parse etcd urls line to array
for _, url := range strings.Split(c.EtcdEndpointsLine, ",") {
c.EtcdEndpoints = append(c.EtcdEndpoints, url)
}
if len(c.EtcdEndpoints) < 1 {
logrus.Error("Must define the etcd endpoints by --etcd-endpoints")
os.Exit(17)
}
// parse values from prometheus options to config
ipPort := strings.TrimLeft(c.AdvertiseAddr, "shttp://")
ipPortArr := strings.Split(ipPort, ":")
c.BindIP = ipPortArr[0]
port, err := strconv.Atoi(ipPortArr[1])
if err == nil {
c.Port = port
}
defaultOptions := "--log.level=%s --web.listen-address=%s --config.file=%s --storage.tsdb.path=%s --storage.tsdb.retention.time=%s"
defaultOptions = fmt.Sprintf(defaultOptions, c.LogLevel, c.Web.ListenAddress, c.ConfigFile, c.LocalStoragePath, c.Tsdb.Retention)
if c.Tsdb.NoLockfile {

View File

@ -24,10 +24,8 @@ import (
"syscall"
"github.com/goodrain/rainbond/cmd/mq/option"
discover "github.com/goodrain/rainbond/discover.v2"
"github.com/goodrain/rainbond/mq/api"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
@ -43,35 +41,8 @@ func Run(s *option.MQServer) error {
apiManager.Start(errChan)
defer apiManager.Stop()
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: s.Config.EtcdEndPoints,
CaFile: s.Config.EtcdCaFile,
CertFile: s.Config.EtcdCertFile,
KeyFile: s.Config.EtcdKeyFile,
}
//step 2:regist mq endpoint
keepalive, err := discover.CreateKeepAlive(etcdClientArgs, "rainbond_mq", s.Config.HostName, s.Config.HostIP, s.Config.APIPort)
if err != nil {
return err
}
if err := keepalive.Start(); err != nil {
return err
}
defer keepalive.Stop()
//step 3:regist prometheus export endpoint
exportKeepalive, err := discover.CreateKeepAlive(etcdClientArgs, "mq", s.Config.HostName, s.Config.HostIP, 6301)
if err != nil {
return err
}
if err := exportKeepalive.Start(); err != nil {
return err
}
defer exportKeepalive.Stop()
//step finally: listen Signal
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-term:

View File

@ -42,7 +42,7 @@ var mode string
func main() {
AddFlags(pflag.CommandLine)
pflag.Parse()
c, err := client.NewMqClient(nil, server)
c, err := client.NewMqClient(server)
if err != nil {
logrus.Error("new mq client error.", err.Error())
os.Exit(1)

View File

@ -26,15 +26,14 @@ import (
"github.com/spf13/pflag"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/cmd/node/server"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
"github.com/goodrain/rainbond/cmd/node-proxy/server"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("node")
}
server.ParseClientCommnad(os.Args)
option.Config.AddFlags(pflag.CommandLine)
server.InstallServiceFlags(pflag.CommandLine)
if err := option.Init(); err != nil {

View File

@ -0,0 +1,144 @@
// Copyright (C) 2014-2021 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 option
import (
"context"
"fmt"
"os"
"path"
dockercli "github.com/docker/docker/client"
"github.com/goodrain/rainbond/util"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
var (
//Config config
Config = new(Conf)
initialized bool
)
//Init init config
func Init() error {
if initialized {
return nil
}
pflag.Parse()
Config.SetLog()
if err := Config.parse(); err != nil {
return err
}
initialized = true
return nil
}
//Conf Conf
type Conf struct {
APIAddr string //api server listen port
GrpcAPIAddr string //grpc api server listen port
LogLevel string
LogFile string
StatsdConfig StatsdConfig
UDPMonitorConfig UDPMonitorConfig
//enable collect docker container log
EnableCollectLog bool
DockerCli *dockercli.Client
// Namespace for Rainbond application.
RbdNamespace string
ImageRepositoryHost string
GatewayVIP string
HostsFile string
KubeConfigPath string
}
//StatsdConfig StatsdConfig
type StatsdConfig struct {
StatsdListenAddress string
StatsdListenUDP string
StatsdListenTCP string
MappingConfig string
ReadBuffer int
}
//UDPMonitorConfig UDPMonitorConfig
type UDPMonitorConfig struct {
ListenHost string
ListenPort string
}
//AddFlags AddFlags
func (a *Conf) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&a.LogLevel, "log-level", "info", "the log level")
fs.StringVar(&a.LogFile, "log-file", "", "the log file path that log output")
fs.StringVar(&a.GrpcAPIAddr, "grpc-api-addr", ":6101", "The node grpc api server listen address")
fs.StringVar(&a.StatsdConfig.StatsdListenAddress, "statsd.listen-address", "", "The UDP address on which to receive statsd metric lines. DEPRECATED, use statsd.listen-udp instead.")
fs.StringVar(&a.StatsdConfig.StatsdListenUDP, "statsd.listen-udp", ":9125", "The UDP address on which to receive statsd metric lines. \"\" disables it.")
fs.StringVar(&a.StatsdConfig.StatsdListenTCP, "statsd.listen-tcp", ":9125", "The TCP address on which to receive statsd metric lines. \"\" disables it.")
fs.StringVar(&a.StatsdConfig.MappingConfig, "statsd.mapping-config", "", "Metric mapping configuration file name.")
fs.IntVar(&a.StatsdConfig.ReadBuffer, "statsd.read-buffer", 0, "Size (in bytes) of the operating system's transmit read buffer associated with the UDP connection. Please make sure the kernel parameters net.core.rmem_max is set to a value greater than the value specified.")
fs.BoolVar(&a.EnableCollectLog, "enabel-collect-log", true, "Whether to collect container logs")
fs.StringVar(&a.RbdNamespace, "rbd-ns", "rbd-system", "The namespace of rainbond applications.")
fs.StringVar(&a.ImageRepositoryHost, "image-repo-host", "goodrain.me", "The host of image repository")
fs.StringVar(&a.GatewayVIP, "gateway-vip", "", "The vip of gateway")
fs.StringVar(&a.HostsFile, "hostsfile", "/newetc/hosts", "/etc/hosts mapped path in the container. eg. /etc/hosts:/tmp/hosts. Do not set hostsfile to /etc/hosts")
fs.StringVar(&a.KubeConfigPath, "kubeconfig", "", "path to kubeconfig file with authorization and master location information.")
}
//SetLog 设置log
func (a *Conf) SetLog() {
level, err := logrus.ParseLevel(a.LogLevel)
if err != nil {
fmt.Println("set log level error." + err.Error())
return
}
logrus.SetLevel(level)
if a.LogFile != "" {
if err := util.CheckAndCreateDir(path.Dir(a.LogFile)); err != nil {
logrus.Errorf("create node log file dir failure %s", err.Error())
os.Exit(1)
}
logfile, err := os.OpenFile(a.LogFile, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0755)
if err != nil {
logrus.Errorf("create and open node log file failure %s", err.Error())
os.Exit(1)
}
logrus.SetOutput(logfile)
}
}
//ParseClient handle config and create some api
func (a *Conf) ParseClient(ctx context.Context) (err error) {
a.DockerCli, err = dockercli.NewClientWithOpts(dockercli.FromEnv)
if err != nil {
return err
}
return nil
}
//parse parse
func (a *Conf) parse() error {
//init api listen port, can not custom
if a.APIAddr == "" {
a.APIAddr = ":6100"
}
return nil
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2014-2018 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// RAINBOND, Application Management Platform
// This program is free software: you can redistribute it and/or modify
@ -25,20 +25,14 @@ import (
"os/signal"
"syscall"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
"github.com/goodrain/rainbond/discover.v2"
eventLog "github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/node/api"
"github.com/goodrain/rainbond/node/api/controller"
"github.com/goodrain/rainbond/node/core/store"
"github.com/goodrain/rainbond/node/initiate"
"github.com/goodrain/rainbond/node/kubecache"
"github.com/goodrain/rainbond/node/masterserver"
"github.com/goodrain/rainbond/node/nodem"
"github.com/goodrain/rainbond/node/nodem/docker"
"github.com/goodrain/rainbond/node/nodem/envoy"
"github.com/goodrain/rainbond/util/constants"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/sirupsen/logrus"
"k8s.io/client-go/kubernetes"
@ -55,18 +49,11 @@ func Run(cfg *option.Conf) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: cfg.EtcdEndpoints,
CaFile: cfg.EtcdCaFile,
CertFile: cfg.EtcdCertFile,
KeyFile: cfg.EtcdKeyFile,
DialTimeout: cfg.EtcdDialTimeout,
}
if err := cfg.ParseClient(ctx, etcdClientArgs); err != nil {
if err := cfg.ParseClient(ctx); err != nil {
return fmt.Errorf("config parse error:%s", err.Error())
}
config, err := k8sutil.NewRestConfig(cfg.K8SConfPath)
config, err := k8sutil.NewRestConfig(cfg.KubeConfigPath)
if err != nil {
return err
}
@ -75,35 +62,13 @@ func Run(cfg *option.Conf) error {
return err
}
k8sDiscover := discover.NewK8sDiscover(ctx, clientset, cfg)
defer k8sDiscover.Stop()
nodemanager, err := nodem.NewNodeManager(ctx, cfg)
if err != nil {
return fmt.Errorf("create node manager failed: %s", err)
}
if err := nodemanager.InitStart(); err != nil {
return err
}
err = eventLog.NewManager(eventLog.EventConfig{
EventLogServers: cfg.EventLogServer,
DiscoverArgs: etcdClientArgs,
})
if err != nil {
logrus.Errorf("error creating eventlog manager")
return nil
}
defer eventLog.CloseManager()
logrus.Debug("create and start event log client success")
kubecli, err := kubecache.NewKubeClient(cfg, clientset)
if err != nil {
return err
}
defer kubecli.Stop()
if cfg.ImageRepositoryHost == constants.DefImageRepository {
k8sDiscover := discover.NewK8sDiscover(ctx, clientset, cfg)
defer k8sDiscover.Stop()
hostManager, err := initiate.NewHostManager(cfg, k8sDiscover)
if err != nil {
return fmt.Errorf("create new host manager: %v", err)
@ -117,10 +82,6 @@ func Run(cfg *option.Conf) error {
return fmt.Errorf("sync docker cert from secret error: %s", err.Error())
}
// init etcd client
if err = store.NewClient(ctx, cfg, etcdClientArgs); err != nil {
return fmt.Errorf("Connect to ETCD %s failed: %s", cfg.EtcdEndpoints, err)
}
errChan := make(chan error, 3)
if err := nodemanager.Start(errChan); err != nil {
return fmt.Errorf("start node manager failed: %s", err)
@ -128,24 +89,8 @@ func Run(cfg *option.Conf) error {
defer nodemanager.Stop()
logrus.Debug("create and start node manager moudle success")
//master服务在node服务之后启动
var ms *masterserver.MasterServer
if cfg.RunMode == "master" {
ms, err = masterserver.NewMasterServer(nodemanager.GetCurrentNode(), kubecli)
if err != nil {
logrus.Errorf(err.Error())
return err
}
ms.Cluster.UpdateNode(nodemanager.GetCurrentNode())
if err := ms.Start(errChan); err != nil {
logrus.Errorf(err.Error())
return err
}
defer ms.Stop(nil)
logrus.Debug("create and start master server moudle success")
}
//create api manager
apiManager := api.NewManager(*cfg, nodemanager.GetCurrentNode(), ms, kubecli)
apiManager := api.NewManager(*cfg, clientset)
if err := apiManager.Start(errChan); err != nil {
return err
}
@ -165,10 +110,8 @@ func Run(cfg *option.Conf) error {
defer grpcserver.Stop()
logrus.Debug("create and start api server moudle success")
defer controller.Exist(nil)
//step finally: listen Signal
term := make(chan os.Signal)
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-stoped:

View File

@ -1,5 +1,5 @@
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// Copyright (C) 2014-2021 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
@ -21,7 +21,7 @@
package server
import (
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
"github.com/spf13/pflag"
)

View File

@ -25,7 +25,7 @@ import (
"path/filepath"
"strings"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
utilwindows "github.com/goodrain/rainbond/util/windows"
"github.com/spf13/pflag"
"golang.org/x/sys/windows"

View File

@ -1,260 +0,0 @@
// 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 option
import (
"context"
"flag"
"fmt"
"os"
"path"
"time"
client "github.com/coreos/etcd/clientv3"
dockercli "github.com/docker/docker/client"
"github.com/fsnotify/fsnotify"
"github.com/goodrain/rainbond/util"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
var (
confFile = flag.String("conf",
"conf/files/base.json", "config file path")
//Config config
Config = new(Conf)
initialized bool
watcher *fsnotify.Watcher
exitChan = make(chan struct{})
)
//Init init config
func Init() error {
if initialized {
return nil
}
pflag.Parse()
Config.SetLog()
if err := Config.parse(); err != nil {
return err
}
initialized = true
return nil
}
//Conf Conf
type Conf struct {
APIAddr string //api server listen port
GrpcAPIAddr string //grpc api server listen port
PrometheusAPI string //Prometheus server listen port
K8SConfPath string //absolute path to the kubeconfig file
LogLevel string
LogFile string
HostID string
HostIP string
PodIP string
RunMode string //ACP_NODE 运行模式:master,node
NodeRule string //节点属性 compute manage storage
Service string //服务注册与发现
InitStatus string
NodePath string //Rainbond node model basic information storage path in etcd
EventLogServer []string //event server address list
ConfigStoragePath string //config storage path in etcd
LockPath string
TTL int64 // node heartbeat to master TTL
PodCIDR string //pod cidr, when master not set cidr,this parameter can take effect
EtcdEndpoints []string // etcd endpoints
EtcdDialTimeout time.Duration // etcd dial timeout
EtcdCaFile string // etcd ca file
EtcdCertFile string // etcd cert file
EtcdKeyFile string // etcd key file
StatsdConfig StatsdConfig
UDPMonitorConfig UDPMonitorConfig
MinResyncPeriod time.Duration
AutoUnschedulerUnHealthDuration time.Duration
AutoScheduler bool
ReqTimeout int
// for node controller
ServiceListFile string
ServiceManager string
EnableInitStart bool
AutoRegistNode bool
//enable collect docker container log
EnableCollectLog bool
DockerCli *dockercli.Client
EtcdCli *client.Client
LicPath string
LicSoPath string
// EnableImageGC is the trigger of image garbage collection.
EnableImageGC bool
// imageMinimumGCAge is the minimum age for an unused image before it is
// garbage collected.
ImageMinimumGCAge time.Duration
// imageGCHighThresholdPercent is the percent of disk usage after which
// image garbage collection is always run. The percent is calculated as
// this field value out of 100.
ImageGCHighThresholdPercent int32
// imageGCLowThresholdPercent is the percent of disk usage before which
// image garbage collection is never run. Lowest disk usage to garbage
// collect to. The percent is calculated as this field value out of 100.
ImageGCLowThresholdPercent int32
// ImageGCPeriod is the period for performing image garbage collection.
ImageGCPeriod time.Duration
// Namespace for Rainbond application.
RbdNamespace string
ImageRepositoryHost string
GatewayVIP string
HostsFile string
}
//StatsdConfig StatsdConfig
type StatsdConfig struct {
StatsdListenAddress string
StatsdListenUDP string
StatsdListenTCP string
MappingConfig string
ReadBuffer int
}
//UDPMonitorConfig UDPMonitorConfig
type UDPMonitorConfig struct {
ListenHost string
ListenPort string
}
//AddFlags AddFlags
func (a *Conf) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&a.LogLevel, "log-level", "info", "the log level")
fs.StringVar(&a.LogFile, "log-file", "", "the log file path that log output")
fs.StringVar(&a.PrometheusAPI, "prometheus", "http://rbd-monitor:9999", "the prometheus server address")
fs.StringVar(&a.NodePath, "nodePath", "/rainbond/nodes", "the path of node in etcd")
fs.StringVar(&a.HostID, "nodeid", "", "the unique ID for this node. Just specify, don't modify")
fs.StringVar(&a.HostIP, "hostIP", "", "the host ip you can define. default get ip from eth0")
fs.StringVar(&a.PodIP, "podIP", "", "The pod ip of node.")
fs.StringSliceVar(&a.EventLogServer, "event-log-server", []string{"127.0.0.1:6366"}, "host:port slice of event log server")
fs.StringVar(&a.ConfigStoragePath, "config-path", "/rainbond/acp_configs", "the path of config to store(new)")
fs.StringVar(&a.Service, "servicePath", "/traefik/backends", "the path of service info to store")
fs.StringSliceVar(&a.EtcdEndpoints, "etcd", []string{"http://127.0.0.1:2379"}, "the path of node in etcd")
fs.StringVar(&a.EtcdCaFile, "etcd-ca", "", "verify etcd certificates of TLS-enabled secure servers using this CA bundle")
fs.StringVar(&a.EtcdCertFile, "etcd-cert", "", "identify secure etcd client using this TLS certificate file")
fs.StringVar(&a.EtcdKeyFile, "etcd-key", "", "identify secure etcd client using this TLS key file")
fs.DurationVar(&a.EtcdDialTimeout, "etcd-dialTimeOut", 3, "etcd cluster dialTimeOut In seconds")
fs.IntVar(&a.ReqTimeout, "reqTimeOut", 2, "req TimeOut.")
fs.Int64Var(&a.TTL, "ttl", 10, "Frequency of node status reporting to master")
//fs.StringVar(&a.APIAddr, "api-addr", ":6100", "The node api server listen address")
fs.StringVar(&a.GrpcAPIAddr, "grpc-api-addr", ":6101", "The node grpc api server listen address")
fs.StringVar(&a.K8SConfPath, "kube-conf", "", "absolute path to the kubeconfig file ./kubeconfig")
fs.StringVar(&a.RunMode, "run-mode", "worker", "the acp_node run mode,could be 'worker' or 'master'")
fs.StringVar(&a.NodeRule, "noderule", "compute", "current node rule,maybe is `compute` `manage` `storage` ")
fs.StringVar(&a.StatsdConfig.StatsdListenAddress, "statsd.listen-address", "", "The UDP address on which to receive statsd metric lines. DEPRECATED, use statsd.listen-udp instead.")
fs.StringVar(&a.StatsdConfig.StatsdListenUDP, "statsd.listen-udp", ":9125", "The UDP address on which to receive statsd metric lines. \"\" disables it.")
fs.StringVar(&a.StatsdConfig.StatsdListenTCP, "statsd.listen-tcp", ":9125", "The TCP address on which to receive statsd metric lines. \"\" disables it.")
fs.StringVar(&a.StatsdConfig.MappingConfig, "statsd.mapping-config", "", "Metric mapping configuration file name.")
fs.IntVar(&a.StatsdConfig.ReadBuffer, "statsd.read-buffer", 0, "Size (in bytes) of the operating system's transmit read buffer associated with the UDP connection. Please make sure the kernel parameters net.core.rmem_max is set to a value greater than the value specified.")
fs.DurationVar(&a.MinResyncPeriod, "min-resync-period", time.Second*15, "The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod")
fs.StringVar(&a.ServiceListFile, "service-list-file", "/opt/rainbond/conf/", "Specifies the configuration file, which can be a directory, that configures the service running on the current node")
fs.BoolVar(&a.EnableInitStart, "enable-init-start", false, "Enable dependency - free initialization starts for services that support initialization starts")
fs.BoolVar(&a.AutoRegistNode, "auto-registnode", true, "Whether auto regist node info to cluster where node is not found")
fs.BoolVar(&a.AutoScheduler, "auto-scheduler", true, "Whether auto set node unscheduler where current node is unhealth")
fs.BoolVar(&a.EnableCollectLog, "enabel-collect-log", true, "Whether to collect container logs")
fs.DurationVar(&a.AutoUnschedulerUnHealthDuration, "autounscheduler-unhealthy-dura", 5*time.Minute, "Node unhealthy duration, after the automatic offline,if set 0,disable auto handle unscheduler.default is 5 Minute")
fs.StringVar(&a.LicPath, "lic-path", "/opt/rainbond/etc/license/license.yb", "the license path of the enterprise version.")
fs.StringVar(&a.LicSoPath, "lic-so-path", "/opt/rainbond/etc/license/license.so", "Dynamic library file path for parsing the license.")
fs.BoolVar(&a.EnableImageGC, "enable-image-gc", true, "The trigger of image garbage collection.")
fs.DurationVar(&a.ImageMinimumGCAge, "minimum-image-ttl-duration", 2*time.Hour, "Minimum age for an unused image before it is garbage collected. Examples: '300ms', '10s' or '2h45m'.")
fs.DurationVar(&a.ImageGCPeriod, "image-gc-period", 5*time.Minute, "ImageGCPeriod is the period for performing image garbage collection. Examples: '10s', '5m' or '2h45m'.")
fs.Int32Var(&a.ImageGCHighThresholdPercent, "image-gc-high-threshold", 90, "The percent of disk usage after which image garbage collection is always run. Values must be within the range [0, 100], To disable image garbage collection, set to 100. ")
fs.Int32Var(&a.ImageGCLowThresholdPercent, "image-gc-low-threshold", 75, "The percent of disk usage before which image garbage collection is never run. Lowest disk usage to garbage collect to. Values must be within the range [0, 100] and should not be larger than that of --image-gc-high-threshold.")
fs.StringVar(&a.RbdNamespace, "rbd-ns", "rbd-system", "The namespace of rainbond applications.")
fs.StringVar(&a.ImageRepositoryHost, "image-repo-host", "goodrain.me", "The host of image repository")
fs.StringVar(&a.GatewayVIP, "gateway-vip", "", "The vip of gateway")
fs.StringVar(&a.HostsFile, "hostsfile", "/newetc/hosts", "/etc/hosts mapped path in the container. eg. /etc/hosts:/tmp/hosts. Do not set hostsfile to /etc/hosts")
}
//SetLog 设置log
func (a *Conf) SetLog() {
level, err := logrus.ParseLevel(a.LogLevel)
if err != nil {
fmt.Println("set log level error." + err.Error())
return
}
logrus.SetLevel(level)
if a.LogFile != "" {
if err := util.CheckAndCreateDir(path.Dir(a.LogFile)); err != nil {
logrus.Errorf("create node log file dir failure %s", err.Error())
os.Exit(1)
}
logfile, err := os.OpenFile(a.LogFile, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0755)
if err != nil {
logrus.Errorf("create and open node log file failure %s", err.Error())
os.Exit(1)
}
logrus.SetOutput(logfile)
}
}
//ParseClient handle config and create some api
func (a *Conf) ParseClient(ctx context.Context, etcdClientArgs *etcdutil.ClientArgs) (err error) {
a.DockerCli, err = dockercli.NewEnvClient()
if err != nil {
return err
}
logrus.Infof("begin create etcd client: %s", a.EtcdEndpoints)
for {
a.EtcdCli, err = etcdutil.NewClient(ctx, etcdClientArgs)
if err != nil {
logrus.Errorf("create etcd client failure %s, will retry after 3 second", err.Error())
}
if err == nil && a.EtcdCli != nil {
break
}
time.Sleep(time.Second * 3)
}
logrus.Infof("create etcd client success")
return nil
}
//parse parse
func (a *Conf) parse() error {
if a.TTL <= 0 {
a.TTL = 10
}
a.LockPath = "/rainbond/lock"
if a.HostIP == "" || !util.CheckIP(a.HostIP) {
localIP, err := util.LocalIP()
if localIP == nil || err != nil {
return fmt.Errorf("can not find ip of this node")
}
a.HostIP = localIP.String()
}
//init api listen port, can not custom
if a.APIAddr == "" {
a.APIAddr = ":6100"
}
if a.HostID == "" {
return fmt.Errorf("kubernetes node id can't empty")
}
return nil
}

View File

@ -1,189 +0,0 @@
// 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 server
import (
"fmt"
"net/http"
"os"
"sort"
"strings"
"github.com/goodrain/rainbond/util"
"github.com/sirupsen/logrus"
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/builder/parser"
"github.com/goodrain/rainbond/node/nodem/service"
"github.com/goodrain/rainbond/cmd"
httputil "github.com/goodrain/rainbond/util/http"
"github.com/urfave/cli"
)
//ParseClientCommnad parse client command
// node service xxx :Operation of the guard component
// node reg : Register the daemon configuration for node
// node run: daemon start node server
func ParseClientCommnad(args []string) {
if len(args) > 1 {
switch args[1] {
case "version":
cmd.ShowVersion("node")
case "service":
controller := controllerServiceClient{}
if len(args) > 2 {
switch args[2] {
case "start":
if len(args) < 4 {
fmt.Printf("Parameter error")
}
//enable a service
serviceName := args[3]
if err := controller.startService(serviceName); err != nil {
fmt.Printf("start service %s failure %s", serviceName, err.Error())
os.Exit(1)
}
fmt.Printf("start service %s success", serviceName)
os.Exit(0)
case "stop":
if len(args) < 4 {
fmt.Printf("Parameter error")
}
//disable a service
serviceName := args[3]
if err := controller.stopService(serviceName); err != nil {
fmt.Printf("stop service %s failure %s", serviceName, err.Error())
os.Exit(1)
}
fmt.Printf("stop service %s success", serviceName)
os.Exit(0)
case "update":
if err := controller.updateConfig(); err != nil {
fmt.Printf("update service config failure %s", err.Error())
os.Exit(1)
}
fmt.Printf("update service config success")
os.Exit(0)
}
}
case "upgrade":
App := cli.NewApp()
App.Version = "0.1"
App.Commands = []cli.Command{
{
Name: "upgrade",
Flags: []cli.Flag{
cli.StringFlag{
Name: "config-dir,c",
Value: "/opt/rainbond/conf",
Usage: "service config file dir",
},
cli.StringFlag{
Name: "new-version,v",
Value: "",
Usage: "upgrade target version",
},
cli.StringFlag{
Name: "image-prefix,p",
Value: "goodrain.me",
Usage: "",
},
cli.StringSliceFlag{
Name: "services,s",
Value: &cli.StringSlice{"rbd-gateway", "rbd-api", "rbd-chaos", "rbd-mq", "rbd-webcli", "rbd-worker", "rbd-eventlog", "rbd-monitor", "rbd-app-ui"},
Usage: "Enable supported services",
},
},
Action: upgradeImages,
},
}
sort.Sort(cli.FlagsByName(App.Flags))
sort.Sort(cli.CommandsByName(App.Commands))
if err := App.Run(os.Args); err != nil {
logrus.Errorf("upgrade failure %s", err.Error())
os.Exit(1)
}
logrus.Info("upgrade success")
os.Exit(0)
case "run":
}
}
}
//upgrade image name
func upgradeImages(ctx *cli.Context) error {
services := service.LoadServicesWithFileFromLocal(ctx.String("c"))
for i, serviceList := range services {
for j, service := range serviceList.Services {
if util.StringArrayContains(ctx.StringSlice("s"), service.Name) &&
service.Start != "" && !service.OnlyHealthCheck {
par := parser.CreateDockerRunOrImageParse("", "", service.Start, nil, event.GetTestLogger())
par.ParseDockerun(service.Start)
image := par.GetImage()
if image.Name == "" {
continue
}
newImage := ctx.String("p") + "/" + service.Name + ":" + ctx.String("v")
oldImage := func() string {
if image.IsOfficial() {
return image.GetRepostory() + ":" + image.GetTag()
}
return image.String()
}()
services[i].Services[j].Start = strings.Replace(services[i].Services[j].Start, oldImage, newImage, 1)
logrus.Infof("upgrade %s image from %s to %s", service.Name, oldImage, newImage)
}
}
}
return service.WriteServicesWithFile(services...)
}
type controllerServiceClient struct {
}
func (c *controllerServiceClient) request(url string) error {
res, err := http.Post(url, "", nil)
if err != nil {
return err
}
if res.StatusCode == 200 {
return nil
}
resbody, err := httputil.ParseResponseBody(res.Body, "application/json")
if err != nil {
return err
}
return fmt.Errorf(resbody.Msg)
}
func (c *controllerServiceClient) startService(serviceName string) error {
return c.request(fmt.Sprintf("http://127.0.0.1:6100/services/%s/start", serviceName))
}
func (c *controllerServiceClient) stopService(serviceName string) error {
return c.request(fmt.Sprintf("http://127.0.0.1:6100/services/%s/stop", serviceName))
}
func (c *controllerServiceClient) updateConfig() error {
return c.request(fmt.Sprintf("http://127.0.0.1:6100/services/update"))
}

View File

@ -1,77 +0,0 @@
// 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 option
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
//Config config server
type Config struct {
EtcdEndPoints []string
EtcdCaFile string
EtcdCertFile string
EtcdKeyFile string
Address string
HostIP string
HostName string
Port int
SessionKey string
PrometheusMetricPath string
K8SConfPath string
}
//WebCliServer container webcli server
type WebCliServer struct {
Config
LogLevel string
}
//NewWebCliServer new server
func NewWebCliServer() *WebCliServer {
return &WebCliServer{}
}
//AddFlags config
func (a *WebCliServer) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&a.LogLevel, "log-level", "info", "the webcli log level")
fs.StringSliceVar(&a.EtcdEndPoints, "etcd-endpoints", []string{"http://127.0.0.1:2379"}, "etcd v3 cluster endpoints.")
fs.StringVar(&a.EtcdCaFile, "etcd-ca", "", "etcd tls ca file ")
fs.StringVar(&a.EtcdCertFile, "etcd-cert", "", "etcd tls cert file")
fs.StringVar(&a.EtcdKeyFile, "etcd-key", "", "etcd http tls cert key file")
fs.StringVar(&a.Address, "address", "0.0.0.0", "server listen address")
fs.StringVar(&a.HostIP, "hostIP", "", "Current node Intranet IP")
fs.StringVar(&a.HostName, "hostName", "", "Current node host name")
fs.StringVar(&a.K8SConfPath, "kube-conf", "", "absolute path to the kubeconfig file")
fs.IntVar(&a.Port, "port", 7171, "server listen port")
fs.StringVar(&a.PrometheusMetricPath, "metric", "/metrics", "prometheus metrics path")
}
//SetLog 设置log
func (a *WebCliServer) SetLog() {
level, err := logrus.ParseLevel(a.LogLevel)
if err != nil {
fmt.Println("set log level error." + err.Error())
return
}
logrus.SetLevel(level)
}

View File

@ -1,77 +0,0 @@
// 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 server
import (
"os"
"os/signal"
"strconv"
"syscall"
"github.com/goodrain/rainbond/cmd/webcli/option"
"github.com/goodrain/rainbond/discover"
"github.com/goodrain/rainbond/webcli/app"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
//Run start run
func Run(s *option.WebCliServer) error {
errChan := make(chan error)
option := app.DefaultOptions
option.Address = s.Address
option.Port = strconv.Itoa(s.Port)
option.SessionKey = s.SessionKey
option.K8SConfPath = s.K8SConfPath
ap, err := app.New(&option)
if err != nil {
return err
}
err = ap.Run()
if err != nil {
return err
}
defer ap.Exit()
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: s.EtcdEndPoints,
CaFile: s.EtcdCaFile,
CertFile: s.EtcdCertFile,
KeyFile: s.EtcdKeyFile,
}
keepalive, err := discover.CreateKeepAlive(etcdClientArgs, "acp_webcli", s.HostName, s.HostIP, s.Port)
if err != nil {
return err
}
if err := keepalive.Start(); err != nil {
return err
}
defer keepalive.Stop()
//step finally: listen Signal
term := make(chan os.Signal)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-term:
logrus.Warn("Received SIGTERM, exiting gracefully...")
case err := <-errChan:
logrus.Errorf("Received a error %s, exiting gracefully...", err.Error())
}
logrus.Info("See you next time!")
return nil
}

View File

@ -1,44 +0,0 @@
// 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 main
import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/webcli/option"
"github.com/goodrain/rainbond/cmd/webcli/server"
"github.com/spf13/pflag"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("webcli")
}
s := option.NewWebCliServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()
s.SetLog()
if err := server.Run(s); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

View File

@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// +build windows
package option
import (

View File

@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// +build windows
package main
import (

View File

@ -30,12 +30,6 @@ import (
//Config config server
type Config struct {
EtcdEndPoints []string
EtcdCaFile string
EtcdCertFile string
EtcdKeyFile string
EtcdTimeout int
EtcdPrefix string
ClusterName string
MysqlConnectionInfo string
DBType string
@ -81,32 +75,25 @@ func NewWorker() *Worker {
//AddFlags config
func (a *Worker) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&a.LogLevel, "log-level", "info", "the worker log level")
fs.StringSliceVar(&a.EtcdEndPoints, "etcd-endpoints", []string{"http://127.0.0.1:2379"}, "etcd v3 cluster endpoints.")
fs.StringVar(&a.EtcdCaFile, "etcd-ca", "", "")
fs.StringVar(&a.EtcdCertFile, "etcd-cert", "", "")
fs.StringVar(&a.EtcdKeyFile, "etcd-key", "", "")
fs.IntVar(&a.EtcdTimeout, "etcd-timeout", 5, "etcd http timeout seconds")
fs.StringVar(&a.EtcdPrefix, "etcd-prefix", "/store", "the etcd data save key prefix ")
fs.StringVar(&a.PrometheusMetricPath, "metric", "/metrics", "prometheus metrics path")
fs.StringVar(&a.Listen, "listen", ":6369", "prometheus listen host and port")
fs.StringVar(&a.DBType, "db-type", "mysql", "db type mysql or etcd")
fs.StringVar(&a.MysqlConnectionInfo, "mysql", "root:admin@tcp(127.0.0.1:3306)/region", "mysql db connection info")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"127.0.0.1:6366"}, "event log server address. simple lb")
fs.StringSliceVar(&a.EventLogServers, "event-servers", []string{"rbd-eventlog:6366"}, "event log server address. simple lb")
fs.StringVar(&a.KubeConfig, "kube-config", "", "kubernetes api server config file")
fs.IntVar(&a.KubeAPIQPS, "kube-api-qps", 50, "kube client qps")
fs.IntVar(&a.KubeAPIBurst, "kube-api-burst", 10, "kube clint burst")
fs.IntVar(&a.MaxTasks, "max-tasks", 50, "the max tasks for per node")
fs.StringVar(&a.MQAPI, "mq-api", "127.0.0.1:6300", "acp_mq api")
fs.StringVar(&a.MQAPI, "mq-api", "rbd-mq:6300", "acp_mq api")
fs.StringVar(&a.RunMode, "run", "sync", "sync data when worker start")
fs.StringVar(&a.NodeName, "node-name", "", "the name of this worker,it must be global unique name")
fs.StringVar(&a.HostIP, "host-ip", "", "the ip of this worker,it must be global connected ip")
fs.IntVar(&a.ServerPort, "server-port", 6535, "the listen port that app runtime server")
fs.StringVar(&a.LeaderElectionNamespace, "leader-election-namespace", "rainbond", "Namespace where this attacher runs.")
fs.StringVar(&a.LeaderElectionNamespace, "leader-election-namespace", "rbd-system", "Namespace where this attacher runs.")
fs.StringVar(&a.LeaderElectionIdentity, "leader-election-identity", "", "Unique idenity of this attcher. Typically name of the pod where the attacher runs.")
fs.StringVar(&a.RBDNamespace, "rbd-system-namespace", "rbd-system", "rbd components kubernetes namespace")
fs.StringVar(&a.GrdataPVCName, "grdata-pvc-name", "rbd-cpt-grdata", "The name of grdata persistent volume claim")
fs.StringVar(&a.Helm.DataDir, "helm-data-dir", "helm-data-dir", "The data directory of Helm.")
if a.Helm.DataDir == "" {
a.Helm.DataDir = "/grdata/helm"
}

View File

@ -30,7 +30,6 @@ import (
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/pkg/common"
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
etcdutil "github.com/goodrain/rainbond/util/etcd"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/goodrain/rainbond/worker/appm/componentdefinition"
"github.com/goodrain/rainbond/worker/appm/controller"
@ -52,23 +51,14 @@ func Run(s *option.Worker) error {
dbconfig := config.Config{
DBType: s.Config.DBType,
MysqlConnectionInfo: s.Config.MysqlConnectionInfo,
EtcdEndPoints: s.Config.EtcdEndPoints,
EtcdTimeout: s.Config.EtcdTimeout,
}
//step 1:db manager init ,event log client init
if err := db.CreateManager(dbconfig); err != nil {
return err
}
defer db.CloseManager()
etcdClientArgs := &etcdutil.ClientArgs{
Endpoints: s.Config.EtcdEndPoints,
CaFile: s.Config.EtcdCaFile,
CertFile: s.Config.EtcdCertFile,
KeyFile: s.Config.EtcdKeyFile,
}
if err := event.NewManager(event.EventConfig{
EventLogServers: s.Config.EventLogServers,
DiscoverArgs: etcdClientArgs,
}); err != nil {
return err
}

View File

@ -1,178 +0,0 @@
// 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 db
import (
"context"
"fmt"
dbconfig "github.com/goodrain/rainbond/db/config"
"github.com/goodrain/rainbond/db/model"
"github.com/goodrain/rainbond/util"
"github.com/testcontainers/testcontainers-go"
"testing"
"time"
)
func TestEndpointDaoImpl_UpdateModel(t *testing.T) {
dbname := "region"
rootpw := "rainbond"
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "mariadb",
ExposedPorts: []string{"3306/tcp"},
Env: map[string]string{
"MYSQL_ROOT_PASSWORD": rootpw,
"MYSQL_DATABASE": dbname,
},
Cmd: []string{"character-set-server=utf8mb4", "collation-server=utf8mb4_unicode_ci"},
}
mariadb, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatal(err)
}
defer mariadb.Terminate(ctx)
host, err := mariadb.Host(ctx)
if err != nil {
t.Error(err)
}
port, err := mariadb.MappedPort(ctx, "3306")
if err != nil {
t.Error(err)
}
connInfo := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", "root",
rootpw, host, port.Int(), dbname)
tryTimes := 3
for {
if err := CreateManager(dbconfig.Config{
DBType: "mysql",
MysqlConnectionInfo: connInfo,
}); err != nil {
if tryTimes == 0 {
t.Fatalf("Connect info: %s; error creating db manager: %v", connInfo, err)
} else {
tryTimes = tryTimes - 1
time.Sleep(10 * time.Second)
continue
}
}
break
}
trueVal := true
falseVal := false
ep := &model.Endpoint{
UUID: util.NewUUID(),
ServiceID: util.NewUUID(),
IP: "10.10.10.10",
IsOnline: &trueVal,
}
err = GetManager().EndpointsDao().AddModel(ep)
if err != nil {
t.Fatalf("error adding endpoint: %v", err)
}
ep.IsOnline = &falseVal
err = GetManager().EndpointsDao().UpdateModel(ep)
if err != nil {
t.Fatalf("error updating endpoint: %v", err)
}
e, err := GetManager().EndpointsDao().GetByUUID(ep.UUID)
if err != nil {
t.Fatalf("error getting endpoint: %v", err)
}
if *e.IsOnline != false {
t.Errorf("Expected %v for e.IsOnline, but returned %v", false, e.IsOnline)
}
}
func TestEndpointDaoImpl_AddModel(t *testing.T) {
dbname := "region"
rootpw := "rainbond"
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "mariadb",
ExposedPorts: []string{"3306/tcp"},
Env: map[string]string{
"MYSQL_ROOT_PASSWORD": rootpw,
"MYSQL_DATABASE": dbname,
},
Cmd: []string{"character-set-server=utf8mb4", "collation-server=utf8mb4_unicode_ci"},
}
mariadb, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatal(err)
}
defer mariadb.Terminate(ctx)
host, err := mariadb.Host(ctx)
if err != nil {
t.Fatal(err)
}
port, err := mariadb.MappedPort(ctx, "3306")
if err != nil {
t.Fatal(err)
}
connInfo := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", "root",
rootpw, host, port.Int(), dbname)
tryTimes := 3
for {
if err := CreateManager(dbconfig.Config{
DBType: "mysql",
MysqlConnectionInfo: connInfo,
}); err != nil {
if tryTimes == 0 {
t.Fatalf("Connect info: %s; error creating db manager: %v", connInfo, err)
} else {
tryTimes = tryTimes - 1
time.Sleep(10 * time.Second)
continue
}
}
break
}
falseVal := false
ep := &model.Endpoint{
UUID: util.NewUUID(),
ServiceID: util.NewUUID(),
IP: "10.10.10.10",
IsOnline: &falseVal,
}
err = GetManager().EndpointsDao().AddModel(ep)
if err != nil {
t.Fatalf("error adding endpoint: %v", err)
}
e, err := GetManager().EndpointsDao().GetByUUID(ep.UUID)
if err != nil {
t.Fatalf("error getting endpoint: %v", err)
}
if *e.IsOnline != false {
t.Errorf("Expected %v for e.IsOnline, but returned %v", false, e.IsOnline)
}
}

View File

@ -19,19 +19,9 @@
package discover
import (
"fmt"
"strings"
"sync"
"time"
"github.com/goodrain/rainbond/discover/config"
"golang.org/x/net/context"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/mvcc/mvccpb"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
"github.com/goodrain/rainbond/discover.v2/config"
)
//CallbackUpdate 每次返还变化
@ -58,36 +48,6 @@ type Discover interface {
AddUpdateProject(name string, callback CallbackUpdate)
Stop()
}
//GetDiscover 获取服务发现管理器
func GetDiscover(opt config.DiscoverConfig) (Discover, error) {
if opt.Ctx == nil {
opt.Ctx = context.Background()
}
ctx, cancel := context.WithCancel(opt.Ctx)
client, err := etcdutil.NewClient(ctx, opt.EtcdClientArgs)
if err != nil {
cancel()
return nil, err
}
etcdD := &etcdDiscover{
projects: make(map[string]CallbackUpdate),
ctx: ctx,
cancel: cancel,
client: client,
prefix: "/rainbond/discover",
}
return etcdD, nil
}
type etcdDiscover struct {
projects map[string]CallbackUpdate
lock sync.Mutex
ctx context.Context
cancel context.CancelFunc
client *clientv3.Client
prefix string
}
type defaultCallBackUpdate struct {
endpoints map[string]*config.Endpoint
callback Callback
@ -182,125 +142,3 @@ func (d *defaultCallBackUpdate) UpdateEndpoints(operation config.Operation, endp
func (d *defaultCallBackUpdate) Error(err error) {
d.callback.Error(err)
}
func (e *etcdDiscover) AddProject(name string, callback Callback) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; !ok {
cal := &defaultCallBackUpdate{
callback: callback,
endpoints: make(map[string]*config.Endpoint),
}
e.projects[name] = cal
go e.discover(name, cal)
}
}
func (e *etcdDiscover) AddUpdateProject(name string, callback CallbackUpdate) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; !ok {
e.projects[name] = callback
go e.discover(name, callback)
}
}
func (e *etcdDiscover) Stop() {
e.cancel()
}
func (e *etcdDiscover) removeProject(name string) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; ok {
delete(e.projects, name)
}
}
func (e *etcdDiscover) discover(name string, callback CallbackUpdate) {
ctx, cancel := context.WithCancel(e.ctx)
defer cancel()
endpoints := e.list(name)
if endpoints != nil && len(endpoints) > 0 {
callback.UpdateEndpoints(config.SYNC, endpoints...)
}
watch := e.client.Watch(ctx, fmt.Sprintf("%s/%s", e.prefix, name), clientv3.WithPrefix())
timer := time.NewTimer(time.Second * 20)
defer timer.Stop()
for {
select {
case <-e.ctx.Done():
return
case <-timer.C:
go e.discover(name, callback)
return
case res := <-watch:
if err := res.Err(); err != nil {
callback.Error(err)
logrus.Debugf("monitor discover get watch error: %s, remove this watch target first, and then sleep 10 sec, we will re-watch it", err.Error())
e.removeProject(name)
time.Sleep(10 * time.Second)
e.AddUpdateProject(name, callback)
return
}
for _, event := range res.Events {
if event.Kv != nil {
var end *config.Endpoint
kstep := strings.Split(string(event.Kv.Key), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-1]
serverURL := string(event.Kv.Value)
end = &config.Endpoint{Name: serverName, URL: serverURL, Mode: 0}
}
if end != nil { //获取服务地址
switch event.Type {
case mvccpb.DELETE:
callback.UpdateEndpoints(config.DELETE, end)
case mvccpb.PUT:
if event.Kv.Version == 1 {
callback.UpdateEndpoints(config.ADD, end)
} else {
callback.UpdateEndpoints(config.UPDATE, end)
}
}
}
}
}
timer.Reset(time.Second * 20)
}
}
}
func (e *etcdDiscover) list(name string) []*config.Endpoint {
ctx, cancel := context.WithTimeout(e.ctx, time.Second*10)
defer cancel()
res, err := e.client.Get(ctx, fmt.Sprintf("%s/%s", e.prefix, name), clientv3.WithPrefix())
if err != nil {
logrus.Errorf("list all servers of %s error.%s", name, err.Error())
return nil
}
if res.Count == 0 {
return nil
}
return makeEndpointForKvs(res.Kvs)
}
func makeEndpointForKvs(kvs []*mvccpb.KeyValue) (res []*config.Endpoint) {
var ends = make(map[string]*config.Endpoint)
for _, kv := range kvs {
//获取服务地址
kstep := strings.Split(string(kv.Key), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-1]
serverURL := string(kv.Value)
if en, ok := ends[serverName]; ok {
en.URL = serverURL
} else {
ends[serverName] = &config.Endpoint{Name: serverName, URL: serverURL}
}
}
}
for _, v := range ends {
res = append(res, v)
}
return
}

View File

@ -1,72 +0,0 @@
// 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 discover
import (
"github.com/goodrain/rainbond/discover/config"
"testing"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
func TestAddUpdateProject(t *testing.T) {
etcdClientArgs := &etcdutil.ClientArgs{Endpoints: []string{"127.0.0.1:2379"}}
discover, err := GetDiscover(config.DiscoverConfig{
EtcdClientArgs: etcdClientArgs,
})
if err != nil {
t.Fatal(err)
}
defer discover.Stop()
discover.AddUpdateProject("test", callbackupdate{})
}
func TestAddProject(t *testing.T) {
etcdClientArgs := &etcdutil.ClientArgs{Endpoints: []string{"127.0.0.1:2379"}}
discover, err := GetDiscover(config.DiscoverConfig{
EtcdClientArgs: etcdClientArgs,
})
if err != nil {
t.Fatal(err)
}
defer discover.Stop()
discover.AddProject("test", callback{})
}
type callbackupdate struct {
callback
}
func (c callbackupdate) UpdateEndpoints(operation config.Operation, endpoints ...*config.Endpoint) {
logrus.Info(operation, "////", endpoints)
}
type callback struct {
}
func (c callback) UpdateEndpoints(endpoints ...*config.Endpoint) {
for _, en := range endpoints {
logrus.Infof("%+v", en)
}
}
//when watch occurred error,will exec this method
func (c callback) Error(err error) {
logrus.Error(err.Error())
}

View File

@ -14,8 +14,8 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/discover/config"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
"github.com/goodrain/rainbond/discover.v2/config"
)
type k8sDiscover struct {

View File

@ -6,8 +6,8 @@ import (
"testing"
"time"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/discover/config"
"github.com/goodrain/rainbond/cmd/node-proxy/option"
"github.com/goodrain/rainbond/discover.v2/config"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"

View File

@ -1,162 +0,0 @@
// 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 discover
import (
"context"
"fmt"
"sync"
"time"
"github.com/coreos/etcd/clientv3"
client "github.com/coreos/etcd/clientv3"
"github.com/goodrain/rainbond/util"
etcdutil "github.com/goodrain/rainbond/util/etcd"
grpcutil "github.com/goodrain/rainbond/util/grpc"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/naming"
)
//KeepAlive 服务注册
type KeepAlive struct {
cancel context.CancelFunc
EtcdClientArgs *etcdutil.ClientArgs
ServerName string
HostName string
Endpoint string
TTL int64
LID clientv3.LeaseID
Done chan struct{}
etcdClient *client.Client
gRPCResolver *grpcutil.GRPCResolver
once sync.Once
}
//CreateKeepAlive create keepalive for server
func CreateKeepAlive(etcdClientArgs *etcdutil.ClientArgs, ServerName string, Protocol string, HostIP string, Port int) (*KeepAlive, error) {
if ServerName == "" || Port == 0 {
return nil, fmt.Errorf("servername or serverport can not be empty")
}
if HostIP == "" {
ip, err := util.LocalIP()
if err != nil {
logrus.Errorf("get ip failed,details %s", err.Error())
return nil, err
}
HostIP = ip.String()
}
ctx, cancel := context.WithCancel(context.Background())
etcdclient, err := etcdutil.NewClient(ctx, etcdClientArgs)
if err != nil {
cancel()
return nil, err
}
k := &KeepAlive{
EtcdClientArgs: etcdClientArgs,
ServerName: ServerName,
Endpoint: fmt.Sprintf("%s:%d", HostIP, Port),
TTL: 5,
Done: make(chan struct{}),
etcdClient: etcdclient,
cancel: cancel,
}
if Protocol == "" {
k.Endpoint = fmt.Sprintf("%s:%d", HostIP, Port)
} else {
k.Endpoint = fmt.Sprintf("%s://%s:%d", Protocol, HostIP, Port)
}
return k, nil
}
//Start 开始
func (k *KeepAlive) Start() error {
duration := time.Duration(k.TTL) * time.Second
timer := time.NewTimer(duration)
go func() {
for {
select {
case <-k.Done:
return
case <-timer.C:
if k.LID > 0 {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
defer timer.Reset(duration)
_, err := k.etcdClient.KeepAliveOnce(ctx, k.LID)
if err == nil {
return
}
logrus.Warnf("%s lid[%x] keepAlive err: %s, try to reset...", k.Endpoint, k.LID, err.Error())
k.LID = 0
}()
} else {
if err := k.reg(); err != nil {
logrus.Warnf("%s set lid err: %s, try to reset after %d seconds...", k.Endpoint, err.Error(), k.TTL)
} else {
logrus.Infof("%s set lid[%x] success", k.Endpoint, k.LID)
}
timer.Reset(duration)
}
}
}
}()
return nil
}
func (k *KeepAlive) etcdKey() string {
return fmt.Sprintf("/rainbond/discover/%s", k.ServerName)
}
func (k *KeepAlive) reg() error {
k.gRPCResolver = &grpcutil.GRPCResolver{Client: k.etcdClient}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
resp, err := k.etcdClient.Grant(ctx, k.TTL+3)
if err != nil {
return err
}
if err := k.gRPCResolver.Update(ctx, k.etcdKey(), naming.Update{Op: naming.Add, Addr: k.Endpoint}, clientv3.WithLease(resp.ID)); err != nil {
return err
}
logrus.Infof("Register a %s server endpoint %s to cluster", k.ServerName, k.Endpoint)
k.LID = resp.ID
return nil
}
//Stop 结束
func (k *KeepAlive) Stop() {
k.once.Do(func() {
close(k.Done)
k.cancel()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if k.gRPCResolver != nil {
if err := k.gRPCResolver.Update(ctx, k.etcdKey(), naming.Update{Op: naming.Delete, Addr: k.Endpoint}); err != nil {
logrus.Errorf("cancel %s server endpoint %s from etcd error %s", k.ServerName, k.Endpoint, err.Error())
} else {
logrus.Infof("cancel %s server endpoint %s from etcd", k.ServerName, k.Endpoint)
}
}
})
}

View File

@ -1,2 +0,0 @@
## 数据中心内部服务发现包
基于ETCD实现

View File

@ -1,50 +0,0 @@
// 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 config
import "context"
import etcdutil "github.com/goodrain/rainbond/util/etcd"
//Operation 实例操作类型
type Operation int
const (
// ADD add operation
ADD Operation = iota
// DELETE delete operation
DELETE
// UPDATE update operation
UPDATE
// SYNC sync operation
SYNC
)
//DiscoverConfig discover config
type DiscoverConfig struct {
Ctx context.Context
EtcdClientArgs *etcdutil.ClientArgs
}
// Endpoint endpoint
type Endpoint struct {
Name string `json:"name"`
URL string `json:"url"`
Weight int `json:"weight"`
Mode int `json:"-"` //0 表示URL变化1表示Weight变化 ,2表示全变化
}

View File

@ -1,315 +0,0 @@
// 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 discover
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/goodrain/rainbond/util/watch"
"github.com/goodrain/rainbond/discover/config"
"golang.org/x/net/context"
"github.com/coreos/etcd/mvcc/mvccpb"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
//CallbackUpdate 每次返还变化
type CallbackUpdate interface {
//TODO:
//weight自动发现更改实现暂时不 Ready
UpdateEndpoints(operation config.Operation, endpoints ...*config.Endpoint)
//when watch occurred error,will exec this method
Error(error)
}
//Callback 每次返回全部节点
type Callback interface {
UpdateEndpoints(endpoints ...*config.Endpoint)
//when watch occurred error,will exec this method
Error(error)
}
//Discover 后端服务自动发现
type Discover interface {
AddProject(name string, callback Callback)
AddUpdateProject(name string, callback CallbackUpdate)
Stop()
}
//GetDiscover 获取服务发现管理器
func GetDiscover(opt config.DiscoverConfig) (Discover, error) {
if opt.Ctx == nil {
opt.Ctx = context.Background()
}
ctx, cancel := context.WithCancel(opt.Ctx)
client, err := etcdutil.NewClient(ctx, opt.EtcdClientArgs)
if err != nil {
cancel()
return nil, err
}
watcher := watch.New(client, "")
etcdD := &etcdDiscover{
projects: make(map[string]CallbackUpdate),
ctx: ctx,
cancel: cancel,
watcher: watcher,
prefix: "/traefik",
}
return etcdD, nil
}
type etcdDiscover struct {
projects map[string]CallbackUpdate
lock sync.Mutex
ctx context.Context
cancel context.CancelFunc
watcher watch.Watch
prefix string
}
type defaultCallBackUpdate struct {
endpoints map[string]*config.Endpoint
callback Callback
lock sync.Mutex
}
func (d *defaultCallBackUpdate) UpdateEndpoints(operation config.Operation, endpoints ...*config.Endpoint) {
d.lock.Lock()
defer d.lock.Unlock()
switch operation {
case config.ADD:
for _, e := range endpoints {
if old, ok := d.endpoints[e.Name]; !ok {
d.endpoints[e.Name] = e
} else {
if e.Mode == 0 {
old.URL = e.URL
}
if e.Mode == 1 {
old.Weight = e.Weight
}
if e.Mode == 2 {
old.URL = e.URL
old.Weight = e.Weight
}
}
}
case config.SYNC:
for _, e := range endpoints {
if old, ok := d.endpoints[e.Name]; !ok {
d.endpoints[e.Name] = e
} else {
if e.Mode == 0 {
old.URL = e.URL
}
if e.Mode == 1 {
old.Weight = e.Weight
}
if e.Mode == 2 {
old.URL = e.URL
old.Weight = e.Weight
}
}
}
case config.DELETE:
for _, e := range endpoints {
if e.Mode == 0 {
if old, ok := d.endpoints[e.Name]; ok {
old.URL = ""
}
}
if e.Mode == 1 {
if old, ok := d.endpoints[e.Name]; ok {
old.Weight = 0
}
}
if e.Mode == 2 {
if _, ok := d.endpoints[e.Name]; ok {
delete(d.endpoints, e.Name)
}
}
}
case config.UPDATE:
for _, e := range endpoints {
if e.Mode == 0 {
if old, ok := d.endpoints[e.Name]; ok {
old.URL = e.URL
}
}
if e.Mode == 1 {
if old, ok := d.endpoints[e.Name]; ok {
old.Weight = e.Weight
}
}
if e.Mode == 2 {
if old, ok := d.endpoints[e.Name]; ok {
old.URL = e.URL
old.Weight = e.Weight
}
}
}
}
var re []*config.Endpoint
for _, v := range d.endpoints {
if v.URL != "" {
re = append(re, v)
}
}
d.callback.UpdateEndpoints(re...)
}
func (d *defaultCallBackUpdate) Error(err error) {
d.callback.Error(err)
}
func (e *etcdDiscover) AddProject(name string, callback Callback) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; !ok {
cal := &defaultCallBackUpdate{
callback: callback,
endpoints: make(map[string]*config.Endpoint),
}
e.projects[name] = cal
go e.discover(name, cal)
}
}
func (e *etcdDiscover) AddUpdateProject(name string, callback CallbackUpdate) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; !ok {
e.projects[name] = callback
go e.discover(name, callback)
}
}
func (e *etcdDiscover) Stop() {
e.cancel()
}
func (e *etcdDiscover) removeProject(name string) {
e.lock.Lock()
defer e.lock.Unlock()
if _, ok := e.projects[name]; ok {
delete(e.projects, name)
}
}
func (e *etcdDiscover) discover(name string, callback CallbackUpdate) {
watchChan, err := e.watcher.WatchList(e.ctx, fmt.Sprintf("%s/backends/%s/servers", e.prefix, name), "")
if err != nil {
callback.Error(err)
e.removeProject(name)
return
}
defer watchChan.Stop()
for event := range watchChan.ResultChan() {
if event.Source == nil {
continue
}
var end *config.Endpoint
if strings.HasSuffix(event.GetKey(), "/url") { //服务地址变化
kstep := strings.Split(event.GetKey(), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-2]
serverURL := event.GetValueString()
end = &config.Endpoint{Name: serverName, URL: serverURL, Mode: 0}
}
}
if strings.HasSuffix(event.GetKey(), "/weight") { //获取服务地址
kstep := strings.Split(event.GetKey(), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-2]
serverWeight := event.GetValueString()
weight, _ := strconv.Atoi(serverWeight)
end = &config.Endpoint{Name: serverName, Weight: weight, Mode: 1}
}
}
switch event.Type {
case watch.Added:
if end != nil {
callback.UpdateEndpoints(config.ADD, end)
}
case watch.Modified:
if end != nil {
callback.UpdateEndpoints(config.UPDATE, end)
}
case watch.Deleted:
if end != nil {
callback.UpdateEndpoints(config.DELETE, end)
}
case watch.Error:
callback.Error(event.Error)
logrus.Errorf("monitor discover get watch error: %s, remove this watch target first, and then sleep 10 sec, we will re-watch it", event.Error.Error())
e.removeProject(name)
time.Sleep(10 * time.Second)
e.AddUpdateProject(name, callback)
return
}
}
}
func makeEndpointForKvs(kvs []*mvccpb.KeyValue) (res []*config.Endpoint) {
var ends = make(map[string]*config.Endpoint)
for _, kv := range kvs {
if strings.HasSuffix(string(kv.Key), "/url") { //获取服务地址
kstep := strings.Split(string(kv.Key), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-2]
serverURL := string(kv.Value)
if en, ok := ends[serverName]; ok {
en.URL = serverURL
} else {
ends[serverName] = &config.Endpoint{Name: serverName, URL: serverURL}
}
}
}
if strings.HasSuffix(string(kv.Key), "/weight") { //获取服务权重
kstep := strings.Split(string(kv.Key), "/")
if len(kstep) > 2 {
serverName := kstep[len(kstep)-2]
serverWeight := string(kv.Value)
if en, ok := ends[serverName]; ok {
var err error
en.Weight, err = strconv.Atoi(serverWeight)
if err != nil {
logrus.Error("get server weight error.", err.Error())
}
} else {
weight, err := strconv.Atoi(serverWeight)
if err != nil {
logrus.Error("get server weight error.", err.Error())
}
ends[serverName] = &config.Endpoint{Name: serverName, Weight: weight}
}
}
}
}
for _, v := range ends {
res = append(res, v)
}
return
}

View File

@ -1,73 +0,0 @@
// 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 discover
import (
"testing"
"github.com/goodrain/rainbond/discover/config"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
func TestAddUpdateProject(t *testing.T) {
etcdClientArgs := &etcdutil.ClientArgs{Endpoints: []string{"127.0.0.1:2379"}}
discover, err := GetDiscover(config.DiscoverConfig{
EtcdClientArgs: etcdClientArgs,
})
if err != nil {
t.Fatal(err)
}
defer discover.Stop()
discover.AddUpdateProject("test", callbackupdate{})
}
func TestAddProject(t *testing.T) {
etcdClientArgs := &etcdutil.ClientArgs{Endpoints: []string{"127.0.0.1:2379"}}
discover, err := GetDiscover(config.DiscoverConfig{
EtcdClientArgs: etcdClientArgs,
})
if err != nil {
t.Fatal(err)
}
defer discover.Stop()
discover.AddProject("test", callback{})
}
type callbackupdate struct {
callback
}
func (c callbackupdate) UpdateEndpoints(operation config.Operation, endpoints ...*config.Endpoint) {
logrus.Info(operation, "////", endpoints)
}
type callback struct {
}
func (c callback) UpdateEndpoints(endpoints ...*config.Endpoint) {
for _, en := range endpoints {
logrus.Infof("%+v", en)
}
}
//when watch occurred error,will exec this method
func (c callback) Error(err error) {
logrus.Error(err.Error())
}

View File

@ -1,155 +0,0 @@
// 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 discover
import (
"context"
"fmt"
"os"
"time"
"github.com/coreos/etcd/clientv3"
client "github.com/coreos/etcd/clientv3"
"github.com/goodrain/rainbond/util"
etcdutil "github.com/goodrain/rainbond/util/etcd"
"github.com/sirupsen/logrus"
)
//KeepAlive 服务注册
type KeepAlive struct {
cancel context.CancelFunc
EtcdClentArgs *etcdutil.ClientArgs
ServerName string
HostName string
Endpoint string
TTL int64
LID clientv3.LeaseID
Done chan struct{}
etcdClient *client.Client
}
//CreateKeepAlive create keepalive for server
func CreateKeepAlive(etcdClientArgs *etcdutil.ClientArgs, serverName string, hostName string, HostIP string, Port int) (*KeepAlive, error) {
if serverName == "" || Port == 0 {
return nil, fmt.Errorf("servername or serverport can not be empty")
}
if hostName == "" {
var err error
hostName, err = os.Hostname()
if err != nil {
return nil, err
}
}
if HostIP == "" {
ip, err := util.LocalIP()
if err != nil {
logrus.Errorf("get ip failed,details %s", err.Error())
return nil, err
}
HostIP = ip.String()
}
return &KeepAlive{
EtcdClentArgs: etcdClientArgs,
ServerName: serverName,
HostName: hostName,
Endpoint: fmt.Sprintf("%s:%d", HostIP, Port),
TTL: 10,
Done: make(chan struct{}),
}, nil
}
//Start 开始
func (k *KeepAlive) Start() error {
duration := time.Duration(k.TTL) * time.Second
timer := time.NewTimer(duration)
ctx, cancel := context.WithCancel(context.Background())
etcdclient, err := etcdutil.NewClient(ctx, k.EtcdClentArgs)
if err != nil {
return err
}
k.etcdClient = etcdclient
k.cancel = cancel
go func() {
for {
select {
case <-k.Done:
return
case <-timer.C:
if k.LID > 0 {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
_, err := k.etcdClient.KeepAliveOnce(ctx, k.LID)
if err == nil {
timer.Reset(duration)
return
}
logrus.Warnf("%s lid[%x] keepAlive err: %s, try to reset...", k.Endpoint, k.LID, err.Error())
k.LID = 0
timer.Reset(duration)
}()
} else {
if err := k.reg(); err != nil {
logrus.Warnf("%s set lid err: %s, try to reset after %d seconds...", k.Endpoint, err.Error(), k.TTL)
} else {
logrus.Infof("%s set lid[%x] success", k.Endpoint, k.LID)
}
timer.Reset(duration)
}
}
}
}()
return nil
}
func (k *KeepAlive) etcdKey() string {
return fmt.Sprintf("/traefik/backends/%s/servers/%s/url", k.ServerName, k.HostName)
}
func (k *KeepAlive) reg() error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
resp, err := k.etcdClient.Grant(ctx, k.TTL+3)
if err != nil {
return err
}
if _, err := k.etcdClient.Put(ctx,
k.etcdKey(),
k.Endpoint,
clientv3.WithLease(resp.ID)); err != nil {
return err
}
logrus.Infof("Register a %s server endpoint %s to cluster", k.ServerName, k.Endpoint)
k.LID = resp.ID
return nil
}
//Stop 结束
func (k *KeepAlive) Stop() error {
close(k.Done)
defer k.cancel()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if _, err := k.etcdClient.Delete(ctx, k.etcdKey()); err != nil {
return err
}
logrus.Infof("cancel %s server endpoint %s from etcd", k.ServerName, k.Endpoint)
return nil
}

View File

@ -1,5 +0,0 @@
<svg version="1.1" width="36" height="36" viewBox="0 0 36 36" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>bell-outline-badged</title>
<path class="clr-i-outline--badged clr-i-outline-path-1--badged" d="M18,34.28A2.67,2.67,0,0,0,20.58,32H15.32A2.67,2.67,0,0,0,18,34.28Z"></path><path class="clr-i-outline--badged clr-i-outline-path-2--badged" d="M32.51,27.83A14.4,14.4,0,0,1,30,24.9a12.63,12.63,0,0,1-1.35-4.81V15.15a10.92,10.92,0,0,0-.16-1.79,7.44,7.44,0,0,1-2.24-.84,8.89,8.89,0,0,1,.4,2.64v4.94a14.24,14.24,0,0,0,1.65,5.85,16.17,16.17,0,0,0,2.44,3H5.13a16.17,16.17,0,0,0,2.44-3,14.24,14.24,0,0,0,1.65-5.85V15.15A8.8,8.8,0,0,1,18,6.31a8.61,8.61,0,0,1,4.76,1.44A7.49,7.49,0,0,1,22.5,6c0-.21,0-.42,0-.63a10.58,10.58,0,0,0-3.32-1V3.11a1.33,1.33,0,1,0-2.67,0V4.42A10.81,10.81,0,0,0,7.21,15.15v4.94A12.63,12.63,0,0,1,5.86,24.9a14.4,14.4,0,0,1-2.47,2.93,1,1,0,0,0-.34.75v1.36a1,1,0,0,0,1,1h27.8a1,1,0,0,0,1-1V28.58A1,1,0,0,0,32.51,27.83Z"></path><circle class="clr-i-outline--badged clr-i-outline-path-1--badged clr-i-badge" cx="30" cy="6" r="5"></circle>
<rect x="0" y="0" width="36" height="36" fill-opacity="0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Some files were not shown because too many files have changed in this diff Show More