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  }