Rainbond/node/core/config/datacenter.go
2020-07-18 18:02:05 +08:00

239 lines
6.2 KiB
Go

// Copyright (C) 2014-2018 Goodrain Co., Ltd.
// RAINBOND, Application Management Platform
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package config
import (
"context"
"fmt"
"github.com/coreos/etcd/mvcc/mvccpb"
"github.com/pquerna/ffjson/ffjson"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/node/api/model"
"github.com/goodrain/rainbond/node/core/store"
"github.com/goodrain/rainbond/util"
"github.com/Sirupsen/logrus"
client "github.com/coreos/etcd/clientv3"
)
//DataCenterConfig 数据中心配置
type DataCenterConfig struct {
config *model.GlobalConfig
options *option.Conf
ctx context.Context
cancel context.CancelFunc
//group config 不持久化
groupConfigs map[string]*GroupContext
}
var dataCenterConfig *DataCenterConfig
//GetDataCenterConfig 获取
func GetDataCenterConfig() *DataCenterConfig {
if dataCenterConfig == nil {
return CreateDataCenterConfig()
}
return dataCenterConfig
}
//CreateDataCenterConfig 创建
func CreateDataCenterConfig() *DataCenterConfig {
ctx, cancel := context.WithCancel(context.Background())
dataCenterConfig = &DataCenterConfig{
options: option.Config,
ctx: ctx,
cancel: cancel,
config: &model.GlobalConfig{
Configs: make(map[string]*model.ConfigUnit),
},
groupConfigs: make(map[string]*GroupContext),
}
res, err := store.DefalutClient.Get(dataCenterConfig.options.ConfigStoragePath+"/global", client.WithPrefix())
if err != nil {
logrus.Error("load datacenter config error.", err.Error())
}
if res != nil {
if len(res.Kvs) < 1 {
dgc := &model.GlobalConfig{
Configs: make(map[string]*model.ConfigUnit),
}
dataCenterConfig.config = dgc
} else {
for _, kv := range res.Kvs {
dataCenterConfig.PutConfigKV(kv)
}
}
}
return dataCenterConfig
}
//Start 启动,监听配置变化
func (d *DataCenterConfig) Start() {
go util.Exec(d.ctx, func() error {
ctx, cancel := context.WithCancel(d.ctx)
defer cancel()
logrus.Info("datacenter config listener start")
ch := store.DefalutClient.WatchByCtx(ctx, d.options.ConfigStoragePath+"/global", client.WithPrefix())
for event := range ch {
for _, e := range event.Events {
switch {
case e.IsCreate(), e.IsModify():
d.PutConfigKV(e.Kv)
case e.Type == client.EventTypeDelete:
d.DeleteConfig(util.GetIDFromKey(string(e.Kv.Key)))
}
}
}
return nil
}, 1)
}
//Stop 停止监听
func (d *DataCenterConfig) Stop() {
d.cancel()
logrus.Info("datacenter config listener stop")
}
//GetDataCenterConfig 获取配置
func (d *DataCenterConfig) GetDataCenterConfig() (*model.GlobalConfig, error) {
return d.config, nil
}
//PutDataCenterConfig 更改配置
func (d *DataCenterConfig) PutDataCenterConfig(c *model.GlobalConfig) (err error) {
if c == nil {
return
}
for k, v := range c.Configs {
d.config.Add(*v)
_, err = store.DefalutClient.Put(d.options.ConfigStoragePath+"/global/"+k, v.String())
}
return err
}
//GetConfig 获取全局配置
func (d *DataCenterConfig) GetConfig(name string) *model.ConfigUnit {
return d.config.Get(name)
}
//CacheConfig 更新配置缓存
func (d *DataCenterConfig) CacheConfig(c *model.ConfigUnit) error {
if c.Name == "" {
return fmt.Errorf("config name can not be empty")
}
logrus.Debugf("add config %v", c)
//将值类型由[]interface{} 转 []string
if c.ValueType == "array" {
switch c.Value.(type) {
case []interface{}:
var data []string
for _, v := range c.Value.([]interface{}) {
data = append(data, v.(string))
}
c.Value = data
}
oldC := d.config.Get(c.Name)
if oldC != nil {
switch oldC.Value.(type) {
case string:
value := append(c.Value.([]string), oldC.Value.(string))
util.Deweight(&value)
c.Value = value
case []string:
value := append(c.Value.([]string), oldC.Value.([]string)...)
util.Deweight(&value)
c.Value = value
default:
}
}
}
d.config.Add(*c)
return nil
}
//PutConfig 增加or更新配置
func (d *DataCenterConfig) PutConfig(c *model.ConfigUnit) error {
if c.Name == "" {
return fmt.Errorf("config name can not be empty")
}
logrus.Debugf("add config %v", c)
//将值类型由[]interface{} 转 []string
if c.ValueType == "array" {
switch c.Value.(type) {
case []interface{}:
var data []string
for _, v := range c.Value.([]interface{}) {
data = append(data, v.(string))
}
c.Value = data
}
oldC := d.config.Get(c.Name)
if oldC != nil {
switch oldC.Value.(type) {
case string:
value := append(c.Value.([]string), oldC.Value.(string))
util.Deweight(&value)
c.Value = value
case []string:
value := append(c.Value.([]string), oldC.Value.([]string)...)
util.Deweight(&value)
c.Value = value
default:
}
}
}
d.config.Add(*c)
//持久化
_, err := store.DefalutClient.Put(d.options.ConfigStoragePath+"/global/"+c.Name, c.String())
if err != nil {
logrus.Error("put datacenter config to etcd error.", err.Error())
return err
}
return nil
}
//PutConfigKV 更新
func (d *DataCenterConfig) PutConfigKV(kv *mvccpb.KeyValue) {
var cn model.ConfigUnit
if err := ffjson.Unmarshal(kv.Value, &cn); err == nil {
d.CacheConfig(&cn)
} else {
logrus.Errorf("parse config error,%s", err.Error())
}
}
//DeleteConfig 删除配置
func (d *DataCenterConfig) DeleteConfig(name string) {
d.config.Delete(name)
}
//GetGroupConfig get group config
func (d *DataCenterConfig) GetGroupConfig(groupID string) *GroupContext {
if c, ok := d.groupConfigs[groupID]; ok {
return c
}
c := NewGroupContext(groupID)
d.groupConfigs[groupID] = c
return c
}