dubbo.apache.org/dubbo-go/v3@v3.1.1/config/registry_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  	"strconv"
    23  	"strings"
    24  )
    25  
    26  import (
    27  	"github.com/creasty/defaults"
    28  
    29  	"github.com/dubbogo/gost/log/logger"
    30  
    31  	perrors "github.com/pkg/errors"
    32  )
    33  
    34  import (
    35  	"dubbo.apache.org/dubbo-go/v3/common"
    36  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    37  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    38  	"dubbo.apache.org/dubbo-go/v3/config/instance"
    39  	"dubbo.apache.org/dubbo-go/v3/registry"
    40  )
    41  
    42  // RegistryConfig is the configuration of the registry center
    43  type RegistryConfig struct {
    44  	Protocol          string            `validate:"required" yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
    45  	Timeout           string            `default:"5s" validate:"required" yaml:"timeout" json:"timeout,omitempty" property:"timeout"` // unit: second
    46  	Group             string            `yaml:"group" json:"group,omitempty" property:"group"`
    47  	Namespace         string            `yaml:"namespace" json:"namespace,omitempty" property:"namespace"`
    48  	TTL               string            `default:"15m" yaml:"ttl" json:"ttl,omitempty" property:"ttl"` // unit: minute
    49  	Address           string            `validate:"required" yaml:"address" json:"address,omitempty" property:"address"`
    50  	Username          string            `yaml:"username" json:"username,omitempty" property:"username"`
    51  	Password          string            `yaml:"password" json:"password,omitempty"  property:"password"`
    52  	Simplified        bool              `yaml:"simplified" json:"simplified,omitempty"  property:"simplified"`
    53  	Preferred         bool              `yaml:"preferred" json:"preferred,omitempty" property:"preferred"` // Always use this registry first if set to true, useful when subscribe to multiple registriesConfig
    54  	Zone              string            `yaml:"zone" json:"zone,omitempty" property:"zone"`                // The region where the registry belongs, usually used to isolate traffics
    55  	Weight            int64             `yaml:"weight" json:"weight,omitempty" property:"weight"`          // Affects traffic distribution among registriesConfig, useful when subscribe to multiple registriesConfig Take effect only when no preferred registry is specified.
    56  	Params            map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
    57  	RegistryType      string            `yaml:"registry-type"`
    58  	UseAsMetaReport   bool              `default:"true" yaml:"use-as-meta-report" json:"use-as-meta-report,omitempty" property:"use-as-meta-report"`
    59  	UseAsConfigCenter bool              `default:"true" yaml:"use-as-config-center" json:"use-as-config-center,omitempty" property:"use-as-config-center"`
    60  }
    61  
    62  // Prefix dubbo.registries
    63  func (RegistryConfig) Prefix() string {
    64  	return constant.RegistryConfigPrefix
    65  }
    66  
    67  func (c *RegistryConfig) Init() error {
    68  	if err := defaults.Set(c); err != nil {
    69  		return err
    70  	}
    71  	return c.startRegistryConfig()
    72  }
    73  
    74  func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
    75  	urlMap := url.Values{}
    76  	urlMap.Set(constant.RegistryGroupKey, c.Group)
    77  	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(int(roleType)))
    78  	urlMap.Set(constant.RegistryKey, c.Protocol)
    79  	urlMap.Set(constant.RegistryTimeoutKey, c.Timeout)
    80  	// multi registry invoker weight label for load balance
    81  	urlMap.Set(constant.RegistryKey+"."+constant.RegistryLabelKey, strconv.FormatBool(true))
    82  	urlMap.Set(constant.RegistryKey+"."+constant.PreferredKey, strconv.FormatBool(c.Preferred))
    83  	urlMap.Set(constant.RegistryKey+"."+constant.RegistryZoneKey, c.Zone)
    84  	urlMap.Set(constant.RegistryKey+"."+constant.WeightKey, strconv.FormatInt(c.Weight, 10))
    85  	urlMap.Set(constant.RegistryTTLKey, c.TTL)
    86  	urlMap.Set(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address))
    87  
    88  	for k, v := range c.Params {
    89  		urlMap.Set(k, v)
    90  	}
    91  	return urlMap
    92  }
    93  
    94  func (c *RegistryConfig) startRegistryConfig() error {
    95  	c.translateRegistryAddress()
    96  	if c.UseAsMetaReport && isValid(c.Address) {
    97  		if tmpUrl, err := c.toMetadataReportUrl(); err == nil {
    98  			instance.SetMetadataReportInstanceByReg(tmpUrl)
    99  		} else {
   100  			return perrors.Wrap(err, "Start RegistryConfig failed.")
   101  		}
   102  	}
   103  	return verify(c)
   104  }
   105  
   106  // toMetadataReportUrl translate the registry configuration to the metadata reporting url
   107  func (c *RegistryConfig) toMetadataReportUrl() (*common.URL, error) {
   108  	res, err := common.NewURL(c.Address,
   109  		common.WithLocation(c.Address),
   110  		common.WithProtocol(c.Protocol),
   111  		common.WithUsername(c.Username),
   112  		common.WithPassword(c.Password),
   113  		common.WithParamsValue(constant.TimeoutKey, c.Timeout),
   114  		common.WithParamsValue(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address)),
   115  		common.WithParamsValue(constant.MetadataReportGroupKey, c.Group),
   116  		common.WithParamsValue(constant.MetadataReportNamespaceKey, c.Namespace),
   117  	)
   118  	if err != nil || len(res.Protocol) == 0 {
   119  		return nil, perrors.New("Invalid Registry Config.")
   120  	}
   121  	return res, nil
   122  }
   123  
   124  // translateRegistryAddress translate registry address
   125  //
   126  //	eg:address=nacos://127.0.0.1:8848 will return 127.0.0.1:8848 and protocol will set nacos
   127  func (c *RegistryConfig) translateRegistryAddress() string {
   128  	if strings.Contains(c.Address, "://") {
   129  		u, err := url.Parse(c.Address)
   130  		if err != nil {
   131  			logger.Errorf("The registry url is invalid, error: %#v", err)
   132  			panic(err)
   133  		}
   134  		c.Protocol = u.Scheme
   135  		c.Address = strings.Join([]string{u.Host, u.Path}, "")
   136  	}
   137  	return c.Address
   138  }
   139  
   140  func (c *RegistryConfig) GetInstance(roleType common.RoleType) (registry.Registry, error) {
   141  	u, err := c.toURL(roleType)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	// if the protocol == registry, set protocol the registry value in url.params
   146  	if u.Protocol == constant.RegistryProtocol {
   147  		u.Protocol = u.GetParam(constant.RegistryKey, "")
   148  	}
   149  	return extension.GetRegistry(u.Protocol, u)
   150  }
   151  
   152  func (c *RegistryConfig) toURL(roleType common.RoleType) (*common.URL, error) {
   153  	address := c.translateRegistryAddress()
   154  	var registryURLProtocol string
   155  	if c.RegistryType == constant.RegistryTypeService {
   156  		// service discovery protocol
   157  		registryURLProtocol = constant.ServiceRegistryProtocol
   158  	} else if c.RegistryType == constant.RegistryTypeInterface {
   159  		registryURLProtocol = constant.RegistryProtocol
   160  	} else {
   161  		registryURLProtocol = constant.ServiceRegistryProtocol
   162  	}
   163  	return common.NewURL(registryURLProtocol+"://"+address,
   164  		common.WithParams(c.getUrlMap(roleType)),
   165  		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
   166  		common.WithParamsValue(constant.RegistryKey, c.Protocol),
   167  		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
   168  		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
   169  		common.WithUsername(c.Username),
   170  		common.WithPassword(c.Password),
   171  		common.WithLocation(c.Address),
   172  	)
   173  }
   174  
   175  func (c *RegistryConfig) toURLs(roleType common.RoleType) ([]*common.URL, error) {
   176  	address := c.translateRegistryAddress()
   177  	var urls []*common.URL
   178  	var err error
   179  	var registryURL *common.URL
   180  
   181  	if !isValid(c.Address) {
   182  		logger.Infof("Empty or N/A registry address found, the process will work with no registry enabled " +
   183  			"which means that the address of this instance will not be registered and not able to be found by other consumer instances.")
   184  		return urls, nil
   185  	}
   186  
   187  	if c.RegistryType == constant.RegistryTypeService {
   188  		// service discovery protocol
   189  		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
   190  			urls = append(urls, registryURL)
   191  		}
   192  	} else if c.RegistryType == constant.RegistryTypeInterface {
   193  		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
   194  			urls = append(urls, registryURL)
   195  		}
   196  	} else if c.RegistryType == constant.RegistryTypeAll {
   197  		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
   198  			urls = append(urls, registryURL)
   199  		}
   200  		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
   201  			urls = append(urls, registryURL)
   202  		}
   203  	} else {
   204  		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
   205  			urls = append(urls, registryURL)
   206  		}
   207  	}
   208  	return urls, err
   209  }
   210  
   211  func loadRegistries(registryIds []string, registries map[string]*RegistryConfig, roleType common.RoleType) []*common.URL {
   212  	var registryURLs []*common.URL
   213  	//trSlice := strings.Split(targetRegistries, ",")
   214  
   215  	for k, registryConf := range registries {
   216  		target := false
   217  
   218  		// if user not config targetRegistries, default load all
   219  		// Notice: in func "func Split(s, sep string) []string" comment:
   220  		// if s does not contain sep and sep is not empty, SplitAfter returns
   221  		// a slice of length 1 whose only element is s. So we have to add the
   222  		// condition when targetRegistries string is not set (it will be "" when not set)
   223  		if len(registryIds) == 0 || (len(registryIds) == 1 && registryIds[0] == "") {
   224  			target = true
   225  		} else {
   226  			// else if user config targetRegistries
   227  			for _, tr := range registryIds {
   228  				if tr == k {
   229  					target = true
   230  					break
   231  				}
   232  			}
   233  		}
   234  
   235  		if target {
   236  			if urls, err := registryConf.toURLs(roleType); err != nil {
   237  				logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err)
   238  				panic(err)
   239  			} else {
   240  				registryURLs = append(registryURLs, urls...)
   241  			}
   242  		}
   243  	}
   244  
   245  	return registryURLs
   246  }
   247  
   248  func (c *RegistryConfig) createNewURL(protocol string, address string, roleType common.RoleType) (*common.URL, error) {
   249  	return common.NewURL(protocol+"://"+address,
   250  		common.WithParams(c.getUrlMap(roleType)),
   251  		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
   252  		common.WithParamsValue(constant.RegistryKey, c.Protocol),
   253  		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
   254  		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
   255  		common.WithUsername(c.Username),
   256  		common.WithPassword(c.Password),
   257  		common.WithLocation(c.Address),
   258  	)
   259  }
   260  
   261  const (
   262  	defaultZKAddr          = "127.0.0.1:2181" // default registry address of zookeeper
   263  	defaultNacosAddr       = "127.0.0.1:8848" // the default registry address of nacos
   264  	defaultRegistryTimeout = "3s"             // the default registry timeout
   265  )
   266  
   267  type RegistryConfigOpt func(config *RegistryConfig) *RegistryConfig
   268  
   269  // NewRegistryConfigWithProtocolDefaultPort New default registry config
   270  // the input @protocol can only be:
   271  // "zookeeper" with default addr "127.0.0.1:2181"
   272  // "nacos" with default addr "127.0.0.1:8848"
   273  func NewRegistryConfigWithProtocolDefaultPort(protocol string) *RegistryConfig {
   274  	switch protocol {
   275  	case "zookeeper":
   276  		return &RegistryConfig{
   277  			Protocol: protocol,
   278  			Address:  defaultZKAddr,
   279  			Timeout:  defaultRegistryTimeout,
   280  		}
   281  	case "nacos":
   282  		return &RegistryConfig{
   283  			Protocol: protocol,
   284  			Address:  defaultNacosAddr,
   285  			Timeout:  defaultRegistryTimeout,
   286  		}
   287  	default:
   288  		return &RegistryConfig{
   289  			Protocol: protocol,
   290  		}
   291  	}
   292  }
   293  
   294  // NewRegistryConfig creates New RegistryConfig with @opts
   295  func NewRegistryConfig(opts ...RegistryConfigOpt) *RegistryConfig {
   296  	newRegistryConfig := NewRegistryConfigWithProtocolDefaultPort("")
   297  	for _, v := range opts {
   298  		newRegistryConfig = v(newRegistryConfig)
   299  	}
   300  	return newRegistryConfig
   301  }
   302  
   303  // WithRegistryProtocol returns RegistryConfigOpt with given @regProtocol name
   304  func WithRegistryProtocol(regProtocol string) RegistryConfigOpt {
   305  	return func(config *RegistryConfig) *RegistryConfig {
   306  		config.Protocol = regProtocol
   307  		return config
   308  	}
   309  }
   310  
   311  // WithRegistryAddress returns RegistryConfigOpt with given @addr registry address
   312  func WithRegistryAddress(addr string) RegistryConfigOpt {
   313  	return func(config *RegistryConfig) *RegistryConfig {
   314  		config.Address = addr
   315  		return config
   316  	}
   317  }
   318  
   319  // WithRegistryTimeOut returns RegistryConfigOpt with given @timeout registry config
   320  func WithRegistryTimeOut(timeout string) RegistryConfigOpt {
   321  	return func(config *RegistryConfig) *RegistryConfig {
   322  		config.Timeout = timeout
   323  		return config
   324  	}
   325  }
   326  
   327  // WithRegistryGroup returns RegistryConfigOpt with given @group registry group
   328  func WithRegistryGroup(group string) RegistryConfigOpt {
   329  	return func(config *RegistryConfig) *RegistryConfig {
   330  		config.Group = group
   331  		return config
   332  	}
   333  }
   334  
   335  // WithRegistryTTL returns RegistryConfigOpt with given @ttl registry ttl
   336  func WithRegistryTTL(ttl string) RegistryConfigOpt {
   337  	return func(config *RegistryConfig) *RegistryConfig {
   338  		config.TTL = ttl
   339  		return config
   340  	}
   341  }
   342  
   343  // WithRegistryUserName returns RegistryConfigOpt with given @userName registry userName
   344  func WithRegistryUserName(userName string) RegistryConfigOpt {
   345  	return func(config *RegistryConfig) *RegistryConfig {
   346  		config.Username = userName
   347  		return config
   348  	}
   349  }
   350  
   351  // WithRegistryPassword returns RegistryConfigOpt with given @psw registry password
   352  func WithRegistryPassword(psw string) RegistryConfigOpt {
   353  	return func(config *RegistryConfig) *RegistryConfig {
   354  		config.Password = psw
   355  		return config
   356  	}
   357  }
   358  
   359  // WithRegistrySimplified returns RegistryConfigOpt with given @simplified registry simplified flag
   360  func WithRegistrySimplified(simplified bool) RegistryConfigOpt {
   361  	return func(config *RegistryConfig) *RegistryConfig {
   362  		config.Simplified = simplified
   363  		return config
   364  	}
   365  }
   366  
   367  // WithRegistryPreferred returns RegistryConfig with given @preferred registry preferred flag
   368  func WithRegistryPreferred(preferred bool) RegistryConfigOpt {
   369  	return func(config *RegistryConfig) *RegistryConfig {
   370  		config.Preferred = preferred
   371  		return config
   372  	}
   373  }
   374  
   375  // WithRegistryWeight returns RegistryConfigOpt with given @weight registry weight flag
   376  func WithRegistryWeight(weight int64) RegistryConfigOpt {
   377  	return func(config *RegistryConfig) *RegistryConfig {
   378  		config.Weight = weight
   379  		return config
   380  	}
   381  }
   382  
   383  // WithRegistryParams returns RegistryConfigOpt with given registry @params
   384  func WithRegistryParams(params map[string]string) RegistryConfigOpt {
   385  	return func(config *RegistryConfig) *RegistryConfig {
   386  		config.Params = params
   387  		return config
   388  	}
   389  }
   390  
   391  func NewRegistryConfigBuilder() *RegistryConfigBuilder {
   392  	return &RegistryConfigBuilder{
   393  		registryConfig: &RegistryConfig{},
   394  	}
   395  }
   396  
   397  type RegistryConfigBuilder struct {
   398  	registryConfig *RegistryConfig
   399  }
   400  
   401  func (rcb *RegistryConfigBuilder) SetProtocol(protocol string) *RegistryConfigBuilder {
   402  	rcb.registryConfig.Protocol = protocol
   403  	return rcb
   404  }
   405  
   406  func (rcb *RegistryConfigBuilder) SetTimeout(timeout string) *RegistryConfigBuilder {
   407  	rcb.registryConfig.Timeout = timeout
   408  	return rcb
   409  }
   410  
   411  func (rcb *RegistryConfigBuilder) SetGroup(group string) *RegistryConfigBuilder {
   412  	rcb.registryConfig.Group = group
   413  	return rcb
   414  }
   415  
   416  func (rcb *RegistryConfigBuilder) SetNamespace(namespace string) *RegistryConfigBuilder {
   417  	rcb.registryConfig.Namespace = namespace
   418  	return rcb
   419  }
   420  
   421  func (rcb *RegistryConfigBuilder) SetTTL(ttl string) *RegistryConfigBuilder {
   422  	rcb.registryConfig.TTL = ttl
   423  	return rcb
   424  }
   425  
   426  func (rcb *RegistryConfigBuilder) SetAddress(address string) *RegistryConfigBuilder {
   427  	rcb.registryConfig.Address = address
   428  	return rcb
   429  }
   430  
   431  func (rcb *RegistryConfigBuilder) SetUsername(username string) *RegistryConfigBuilder {
   432  	rcb.registryConfig.Username = username
   433  	return rcb
   434  }
   435  
   436  func (rcb *RegistryConfigBuilder) SetPassword(password string) *RegistryConfigBuilder {
   437  	rcb.registryConfig.Password = password
   438  	return rcb
   439  }
   440  
   441  func (rcb *RegistryConfigBuilder) SetSimplified(simplified bool) *RegistryConfigBuilder {
   442  	rcb.registryConfig.Simplified = simplified
   443  	return rcb
   444  }
   445  
   446  func (rcb *RegistryConfigBuilder) SetPreferred(preferred bool) *RegistryConfigBuilder {
   447  	rcb.registryConfig.Preferred = preferred
   448  	return rcb
   449  }
   450  
   451  func (rcb *RegistryConfigBuilder) SetZone(zone string) *RegistryConfigBuilder {
   452  	rcb.registryConfig.Zone = zone
   453  	return rcb
   454  }
   455  
   456  func (rcb *RegistryConfigBuilder) SetWeight(weight int64) *RegistryConfigBuilder {
   457  	rcb.registryConfig.Weight = weight
   458  	return rcb
   459  }
   460  
   461  func (rcb *RegistryConfigBuilder) SetParams(params map[string]string) *RegistryConfigBuilder {
   462  	rcb.registryConfig.Params = params
   463  	return rcb
   464  }
   465  
   466  func (rcb *RegistryConfigBuilder) AddParam(key, value string) *RegistryConfigBuilder {
   467  	if rcb.registryConfig.Params == nil {
   468  		rcb.registryConfig.Params = make(map[string]string)
   469  	}
   470  	rcb.registryConfig.Params[key] = value
   471  	return rcb
   472  }
   473  
   474  func (rcb *RegistryConfigBuilder) SetRegistryType(registryType string) *RegistryConfigBuilder {
   475  	rcb.registryConfig.RegistryType = registryType
   476  	return rcb
   477  }
   478  
   479  func (rcb *RegistryConfigBuilder) Build() *RegistryConfig {
   480  	if err := rcb.registryConfig.Init(); err != nil {
   481  		panic(err)
   482  	}
   483  	return rcb.registryConfig
   484  }
   485  
   486  // DynamicUpdateProperties update registry
   487  func (c *RegistryConfig) DynamicUpdateProperties(updateRegistryConfig *RegistryConfig) {
   488  	// if nacos's registry timeout not equal local root config's registry timeout , update.
   489  	if updateRegistryConfig != nil && updateRegistryConfig.Timeout != c.Timeout {
   490  		c.Timeout = updateRegistryConfig.Timeout
   491  		logger.Infof("RegistryConfigs Timeout was dynamically updated, new value:%v", c.Timeout)
   492  	}
   493  }