dubbo.apache.org/dubbo-go/v3@v3.1.1/config_center/parser/configuration_parser.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 parser 19 20 import ( 21 "strconv" 22 "strings" 23 ) 24 25 import ( 26 "github.com/dubbogo/gost/log/logger" 27 28 "github.com/magiconair/properties" 29 30 perrors "github.com/pkg/errors" 31 32 "gopkg.in/yaml.v2" 33 ) 34 35 import ( 36 "dubbo.apache.org/dubbo-go/v3/common" 37 "dubbo.apache.org/dubbo-go/v3/common/constant" 38 ) 39 40 const ( 41 ScopeApplication = "application" 42 GeneralType = "general" 43 ) 44 45 // ConfigurationParser interface 46 type ConfigurationParser interface { 47 Parse(string) (map[string]string, error) 48 ParseToUrls(content string) ([]*common.URL, error) 49 } 50 51 // DefaultConfigurationParser for supporting properties file in config center 52 type DefaultConfigurationParser struct{} 53 54 // ConfiguratorConfig defines configurator config 55 type ConfiguratorConfig struct { 56 ConfigVersion string `yaml:"configVersion"` 57 Scope string `yaml:"scope"` 58 Key string `yaml:"key"` 59 Enabled bool `yaml:"enabled"` 60 Configs []ConfigItem `yaml:"configs"` 61 } 62 63 // ConfigItem defines config item 64 type ConfigItem struct { 65 Type string `yaml:"type"` 66 Enabled bool `yaml:"enabled"` 67 Addresses []string `yaml:"addresses"` 68 ProviderAddresses []string `yaml:"providerAddresses"` 69 Services []string `yaml:"services"` 70 Applications []string `yaml:"applications"` 71 Parameters map[string]string `yaml:"parameters"` 72 Side string `yaml:"side"` 73 Match *ConditionMatch `yaml:"match"` 74 } 75 76 type ConditionMatch struct { 77 Address *common.AddressMatch `yaml:"address"` 78 ProviderAddress *common.AddressMatch `yaml:"providerAddress"` 79 Service *common.ListStringMatch `yaml:"service"` 80 App *common.ListStringMatch `yaml:"app"` 81 Param []*common.ParamMatch `yaml:"param"` 82 } 83 84 func (c *ConditionMatch) IsMatch(host string, url *common.URL) bool { 85 if !c.Address.IsMatch(host) { 86 return false 87 } 88 if !c.ProviderAddress.IsMatch(url.Location) { 89 return false 90 } 91 if !c.Service.IsMatch(url.ServiceKey()) { 92 return false 93 } 94 if !c.App.IsMatch(url.GetParam(constant.ApplicationKey, "")) { 95 return false 96 } 97 if c.Param != nil { 98 for _, p := range c.Param { 99 if !p.IsMatch(url) { 100 return false 101 } 102 } 103 } 104 return true 105 } 106 107 // Parse load content 108 func (parser *DefaultConfigurationParser) Parse(content string) (map[string]string, error) { 109 pps, err := properties.LoadString(content) 110 if err != nil { 111 logger.Errorf("Parse the content {%v} in DefaultConfigurationParser error ,error message is {%v}", content, err) 112 return nil, err 113 } 114 return pps.Map(), nil 115 } 116 117 // ParseToUrls is used to parse content to urls 118 func (parser *DefaultConfigurationParser) ParseToUrls(content string) ([]*common.URL, error) { 119 config := ConfiguratorConfig{} 120 if err := yaml.Unmarshal([]byte(content), &config); err != nil { 121 return nil, err 122 } 123 scope := config.Scope 124 items := config.Configs 125 var allUrls []*common.URL 126 if scope == ScopeApplication { 127 for _, v := range items { 128 urls, err := appItemToUrls(v, config) 129 if err != nil { 130 return nil, err 131 } 132 allUrls = append(allUrls, urls...) 133 } 134 } else { 135 for _, v := range items { 136 urls, err := serviceItemToUrls(v, config) 137 if err != nil { 138 return nil, err 139 } 140 allUrls = append(allUrls, urls...) 141 } 142 } 143 return allUrls, nil 144 } 145 146 // serviceItemToUrls is used to transfer item and config to urls 147 func serviceItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.URL, error) { 148 addresses := item.Addresses 149 if len(addresses) == 0 { 150 addresses = append(addresses, constant.AnyHostValue) 151 } 152 var urls []*common.URL 153 for _, v := range addresses { 154 urlStr := constant.OverrideProtocol + "://" + v + "/" 155 serviceStr, err := getServiceString(config.Key) 156 if err != nil { 157 return nil, perrors.WithStack(err) 158 } 159 urlStr = urlStr + serviceStr 160 paramStr, err := getParamString(item) 161 if err != nil { 162 return nil, perrors.WithStack(err) 163 } 164 urlStr = urlStr + paramStr 165 urlStr = urlStr + getEnabledString(item, config) 166 urlStr = urlStr + "&category=" 167 urlStr = urlStr + constant.DynamicConfiguratorsCategory 168 urlStr = urlStr + "&configVersion=" 169 urlStr = urlStr + config.ConfigVersion 170 apps := item.Applications 171 if len(apps) > 0 { 172 for _, v := range apps { 173 newUrlStr := urlStr 174 newUrlStr = newUrlStr + "&application" 175 newUrlStr = newUrlStr + v 176 url, err := common.NewURL(newUrlStr) 177 if err != nil { 178 return nil, perrors.WithStack(err) 179 } 180 url.AddAttribute(constant.MatchCondition, item.Match) 181 urls = append(urls, url) 182 } 183 } else { 184 url, err := common.NewURL(urlStr) 185 if err != nil { 186 return nil, perrors.WithStack(err) 187 } 188 url.AddAttribute(constant.MatchCondition, item.Match) 189 urls = append(urls, url) 190 } 191 } 192 return urls, nil 193 } 194 195 // nolint 196 func appItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.URL, error) { 197 addresses := item.Addresses 198 if len(addresses) == 0 { 199 addresses = append(addresses, constant.AnyHostValue) 200 } 201 var urls []*common.URL 202 for _, v := range addresses { 203 urlStr := constant.OverrideProtocol + "://" + v + "/" 204 services := item.Services 205 if len(services) == 0 { 206 services = append(services, constant.AnyValue) 207 } 208 for _, vs := range services { 209 serviceStr, err := getServiceString(vs) 210 if err != nil { 211 return nil, perrors.WithStack(err) 212 } 213 urlStr = urlStr + serviceStr 214 paramStr, err := getParamString(item) 215 if err != nil { 216 return nil, perrors.WithStack(err) 217 } 218 urlStr = urlStr + paramStr 219 urlStr = urlStr + "&application=" 220 urlStr = urlStr + config.Key 221 urlStr = urlStr + getEnabledString(item, config) 222 urlStr = urlStr + "&category=" 223 urlStr = urlStr + constant.AppDynamicConfiguratorsCategory 224 urlStr = urlStr + "&configVersion=" 225 urlStr = urlStr + config.ConfigVersion 226 url, err := common.NewURL(urlStr) 227 if err != nil { 228 return nil, perrors.WithStack(err) 229 } 230 url.AddAttribute(constant.MatchCondition, item.Match) 231 urls = append(urls, url) 232 } 233 } 234 return urls, nil 235 } 236 237 // getServiceString returns service string 238 func getServiceString(service string) (string, error) { 239 if len(service) == 0 { 240 return "", perrors.New("service field in configuration is null.") 241 } 242 var serviceStr string 243 i := strings.Index(service, "/") 244 if i > 0 { 245 serviceStr = serviceStr + "group=" 246 serviceStr = serviceStr + service[0:i] 247 serviceStr = serviceStr + "&" 248 service = service[i+1:] 249 } 250 j := strings.Index(service, ":") 251 if j > 0 { 252 serviceStr = serviceStr + "version=" 253 serviceStr = serviceStr + service[j+1:] 254 serviceStr = serviceStr + "&" 255 service = service[0:j] 256 } 257 serviceStr = service + "?" + serviceStr 258 return serviceStr, nil 259 } 260 261 // nolint 262 func getParamString(item ConfigItem) (string, error) { 263 var retStr string 264 retStr = retStr + "category=" 265 retStr = retStr + constant.DynamicConfiguratorsCategory 266 if len(item.Side) > 0 { 267 retStr = retStr + "&side=" 268 retStr = retStr + item.Side 269 } 270 params := item.Parameters 271 if len(params) <= 0 { 272 return "", perrors.New("Invalid configurator rule, please specify at least one parameter " + 273 "you want to change in the rule.") 274 } 275 for k, v := range params { 276 retStr += "&" + k + "=" + v 277 } 278 279 retStr += "&" + constant.OverrideProvidersKey + "=" + strings.Join(item.ProviderAddresses, ",") 280 281 return retStr, nil 282 } 283 284 // getEnabledString returns enabled string 285 func getEnabledString(item ConfigItem, config ConfiguratorConfig) string { 286 retStr := "&enabled=" 287 if len(item.Type) == 0 || item.Type == GeneralType { 288 retStr = retStr + strconv.FormatBool(config.Enabled) 289 } else { 290 retStr = retStr + strconv.FormatBool(item.Enabled) 291 } 292 return retStr 293 }