dubbo.apache.org/dubbo-go/v3@v3.1.1/config/config_center_config.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package config
    19  
    20  import (
    21  	"net/url"
    22  	"strings"
    23  )
    24  
    25  import (
    26  	"github.com/creasty/defaults"
    27  
    28  	"github.com/dubbogo/gost/log/logger"
    29  
    30  	"github.com/knadh/koanf"
    31  
    32  	"github.com/pkg/errors"
    33  )
    34  
    35  import (
    36  	"dubbo.apache.org/dubbo-go/v3/common"
    37  	conf "dubbo.apache.org/dubbo-go/v3/common/config"
    38  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    39  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    40  	"dubbo.apache.org/dubbo-go/v3/config_center"
    41  	"dubbo.apache.org/dubbo-go/v3/metrics"
    42  	metricsConfigCenter "dubbo.apache.org/dubbo-go/v3/metrics/config_center"
    43  	"dubbo.apache.org/dubbo-go/v3/remoting"
    44  )
    45  
    46  // CenterConfig is configuration for config center
    47  //
    48  // ConfigCenter also introduced concepts of namespace and group to better manage Key-Value pairs by group,
    49  // those configs are already built-in in many professional third-party configuration centers.
    50  // In most cases, namespace is used to isolate different tenants, while group is used to divide the key set from one tenant into groups.
    51  //
    52  // CenterConfig has currently supported Zookeeper, Nacos, Etcd, Consul, Apollo
    53  type CenterConfig struct {
    54  	Protocol  string            `validate:"required" yaml:"protocol"  json:"protocol,omitempty"`
    55  	Address   string            `validate:"required" yaml:"address" json:"address,omitempty"`
    56  	DataId    string            `yaml:"data-id" json:"data-id,omitempty"`
    57  	Cluster   string            `yaml:"cluster" json:"cluster,omitempty"`
    58  	Group     string            `yaml:"group" json:"group,omitempty"`
    59  	Username  string            `yaml:"username" json:"username,omitempty"`
    60  	Password  string            `yaml:"password" json:"password,omitempty"`
    61  	Namespace string            `yaml:"namespace"  json:"namespace,omitempty"`
    62  	AppID     string            `default:"dubbo" yaml:"app-id"  json:"app-id,omitempty"`
    63  	Timeout   string            `default:"10s" yaml:"timeout"  json:"timeout,omitempty"`
    64  	Params    map[string]string `yaml:"params"  json:"parameters,omitempty"`
    65  
    66  	//FileExtension the suffix of config dataId, also the file extension of config content
    67  	FileExtension string `default:"yaml" yaml:"file-extension" json:"file-extension" `
    68  }
    69  
    70  // Prefix dubbo.config-center
    71  func (CenterConfig) Prefix() string {
    72  	return constant.ConfigCenterPrefix
    73  }
    74  
    75  func (c *CenterConfig) check() error {
    76  	if err := defaults.Set(c); err != nil {
    77  		return err
    78  	}
    79  	c.translateConfigAddress()
    80  	return verify(c)
    81  }
    82  
    83  func (c *CenterConfig) Init(rc *RootConfig) error {
    84  	if c == nil {
    85  		return nil
    86  	}
    87  	if err := c.check(); err != nil {
    88  		return err
    89  	}
    90  	return startConfigCenter(rc)
    91  }
    92  
    93  // GetUrlMap gets url map from ConfigCenterConfig
    94  func (c *CenterConfig) GetUrlMap() url.Values {
    95  	urlMap := url.Values{}
    96  	urlMap.Set(constant.ConfigNamespaceKey, c.Namespace)
    97  	urlMap.Set(constant.ConfigGroupKey, c.Group)
    98  	urlMap.Set(constant.ConfigClusterKey, c.Cluster)
    99  	urlMap.Set(constant.ConfigAppIDKey, c.AppID)
   100  	urlMap.Set(constant.ConfigTimeoutKey, c.Timeout)
   101  	urlMap.Set(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address))
   102  
   103  	for key, val := range c.Params {
   104  		urlMap.Set(key, val)
   105  	}
   106  	return urlMap
   107  }
   108  
   109  // translateConfigAddress translate config address
   110  //
   111  //	eg:address=nacos://127.0.0.1:8848 will return 127.0.0.1:8848 and protocol will set nacos
   112  func (c *CenterConfig) translateConfigAddress() string {
   113  	if strings.Contains(c.Address, "://") {
   114  		translatedUrl, err := url.Parse(c.Address)
   115  		if err != nil {
   116  			logger.Errorf("The config address:%s is invalid, error: %#v", c.Address, err)
   117  			panic(err)
   118  		}
   119  		c.Protocol = translatedUrl.Scheme
   120  		c.Address = strings.Replace(c.Address, translatedUrl.Scheme+"://", "", -1)
   121  	}
   122  	return c.Address
   123  }
   124  
   125  // toURL will compatible with baseConfig.ShutdownConfig.Address and baseConfig.ShutdownConfig.RemoteRef before 1.6.0
   126  // After 1.6.0 will not compatible, only baseConfig.ShutdownConfig.RemoteRef
   127  func (c *CenterConfig) toURL() (*common.URL, error) {
   128  	return common.NewURL(c.Address,
   129  		common.WithProtocol(c.Protocol),
   130  		common.WithParams(c.GetUrlMap()),
   131  		common.WithUsername(c.Username),
   132  		common.WithPassword(c.Password),
   133  	)
   134  
   135  }
   136  
   137  // startConfigCenter will start the config center.
   138  // it will prepare the environment
   139  func startConfigCenter(rc *RootConfig) error {
   140  	cc := rc.ConfigCenter
   141  	dynamicConfig, err := cc.GetDynamicConfiguration()
   142  	if err != nil {
   143  		logger.Errorf("[Config Center] Start dynamic configuration center error, error message is %v", err)
   144  		return err
   145  	}
   146  
   147  	strConf, err := dynamicConfig.GetProperties(cc.DataId, config_center.WithGroup(cc.Group))
   148  	if err != nil {
   149  		logger.Warnf("[Config Center] Dynamic config center has started, but config may not be initialized, because: %s", err)
   150  		return nil
   151  	}
   152  	defer metrics.Publish(metricsConfigCenter.NewIncMetricEvent(cc.DataId, cc.Group, remoting.EventTypeAdd, cc.Protocol))
   153  	if len(strConf) == 0 {
   154  		logger.Warnf("[Config Center] Dynamic config center has started, but got empty config with config-center configuration %+v\n"+
   155  			"Please check if your config-center config is correct.", cc)
   156  		return nil
   157  	}
   158  	config := NewLoaderConf(WithDelim("."), WithGenre(cc.FileExtension), WithBytes([]byte(strConf)))
   159  	koan := GetConfigResolver(config)
   160  	if err = koan.UnmarshalWithConf(rc.Prefix(), rc, koanf.UnmarshalConf{Tag: "yaml"}); err != nil {
   161  		return err
   162  	}
   163  
   164  	dynamicConfig.AddListener(cc.DataId, rc, config_center.WithGroup(cc.Group))
   165  	return nil
   166  }
   167  
   168  func (c *CenterConfig) CreateDynamicConfiguration() (config_center.DynamicConfiguration, error) {
   169  	configCenterUrl, err := c.toURL()
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	factory, err := extension.GetConfigCenterFactory(configCenterUrl.Protocol)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	return factory.GetDynamicConfiguration(configCenterUrl)
   178  }
   179  
   180  func (c *CenterConfig) GetDynamicConfiguration() (config_center.DynamicConfiguration, error) {
   181  	envInstance := conf.GetEnvInstance()
   182  	if envInstance.GetDynamicConfiguration() != nil {
   183  		return envInstance.GetDynamicConfiguration(), nil
   184  	}
   185  	dynamicConfig, err := c.CreateDynamicConfiguration()
   186  	if err != nil {
   187  		return nil, errors.WithStack(err)
   188  	}
   189  	envInstance.SetDynamicConfiguration(dynamicConfig)
   190  	return dynamicConfig, nil
   191  }
   192  
   193  func NewConfigCenterConfigBuilder() *ConfigCenterConfigBuilder {
   194  	return &ConfigCenterConfigBuilder{configCenterConfig: newEmptyConfigCenterConfig()}
   195  }
   196  
   197  type ConfigCenterConfigBuilder struct {
   198  	configCenterConfig *CenterConfig
   199  }
   200  
   201  func (ccb *ConfigCenterConfigBuilder) SetProtocol(protocol string) *ConfigCenterConfigBuilder {
   202  	ccb.configCenterConfig.Protocol = protocol
   203  	return ccb
   204  }
   205  
   206  func (ccb *ConfigCenterConfigBuilder) SetUserName(userName string) *ConfigCenterConfigBuilder {
   207  	ccb.configCenterConfig.Username = userName
   208  	return ccb
   209  }
   210  
   211  func (ccb *ConfigCenterConfigBuilder) SetAddress(address string) *ConfigCenterConfigBuilder {
   212  	ccb.configCenterConfig.Address = address
   213  	return ccb
   214  }
   215  
   216  func (ccb *ConfigCenterConfigBuilder) SetPassword(password string) *ConfigCenterConfigBuilder {
   217  	ccb.configCenterConfig.Password = password
   218  	return ccb
   219  }
   220  
   221  func (ccb *ConfigCenterConfigBuilder) SetNamespace(namespace string) *ConfigCenterConfigBuilder {
   222  	ccb.configCenterConfig.Namespace = namespace
   223  	return ccb
   224  }
   225  
   226  func (ccb *ConfigCenterConfigBuilder) SetDataID(dataID string) *ConfigCenterConfigBuilder {
   227  	ccb.configCenterConfig.DataId = dataID
   228  	return ccb
   229  }
   230  
   231  func (ccb *ConfigCenterConfigBuilder) SetGroup(group string) *ConfigCenterConfigBuilder {
   232  	ccb.configCenterConfig.Group = group
   233  	return ccb
   234  }
   235  
   236  func (ccb *ConfigCenterConfigBuilder) Build() *CenterConfig {
   237  	return ccb.configCenterConfig
   238  }
   239  
   240  func newEmptyConfigCenterConfig() *CenterConfig {
   241  	return &CenterConfig{
   242  		Params: make(map[string]string),
   243  	}
   244  }