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 }