Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve tag and configurator rules to keep up with official site #2330

Merged
merged 27 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f27e976
improve tag and configurator rules
chickenlj Jun 7, 2023
9d6939a
ASF header
chickenlj Jun 8, 2023
92a6adf
Merge branch 'main' into router-enhance
chickenlj Jun 19, 2023
2a4625d
add metrics base api interface (#2350)
FoghostCn Jul 7, 2023
12bcf73
Introduce metrics bus (#2351)
FinalT Jul 7, 2023
1f4b1c8
add medata and config center metrics (#2357)
FoghostCn Jul 18, 2023
96dcff5
Merge branch 'main' into feature-metrics
chickenlj Jul 19, 2023
459d2ba
update go mod
chickenlj Jul 19, 2023
667ffcb
Merge branch 'main' into router-enhance
chickenlj Jul 20, 2023
0e4f92f
update unit test
chickenlj Jul 20, 2023
59cb82b
Merge remote-tracking branch 'chickenlj/router-enhance' into router-e…
chickenlj Jul 20, 2023
d0c3564
add metadata rt metrics (#2363)
FoghostCn Jul 26, 2023
82e9849
add registry metrics (#2366)
FinalT Jul 31, 2023
413c894
Merge branch 'main' into feature-metrics
chickenlj Jul 31, 2023
035e2d4
Merge branch 'main' into router-enhance
chickenlj Aug 4, 2023
f5b88b2
Merge branch 'main' of https://github.com/apache/dubbo-go
chickenlj Aug 4, 2023
0c01e72
Merge branch 'main' into router-enhance
chickenlj Aug 4, 2023
59d20f2
ignore Attribute field
chickenlj Aug 6, 2023
cdfb622
Update cluster/router/tag/match.go
chickenlj Aug 15, 2023
2cb8393
Use pointer as receiver
chickenlj Aug 15, 2023
44a83c5
Merge branch 'main' into router-enhance
chickenlj Aug 16, 2023
9da87c7
Merge branch 'main' of https://github.com/apache/dubbo-go
chickenlj Aug 16, 2023
4e52f14
Merge branch 'main' into router-enhance
chickenlj Aug 16, 2023
06f3369
Merge branch 'main' into router-enhance
chickenlj Aug 24, 2023
4fdf50b
unexport url attributes field
chickenlj Aug 24, 2023
eee3001
Merge remote-tracking branch 'chickenlj/router-enhance' into router-e…
chickenlj Aug 24, 2023
9498a4f
Merge branch 'main' into router-enhance
chickenlj Nov 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cluster/router/condition/dynamic_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ func (s *ServiceRouter) Notify(invokers []protocol.Invoker) {
logger.Warnf("config center does not start, please check if the configuration center has been properly configured in dubbogo.yml")
return
}
key := strings.Join([]string{strings.Join([]string{url.Service(), url.GetParam(constant.VersionKey, ""), url.GetParam(constant.GroupKey, "")}, ":"),
constant.ConditionRouterRuleSuffix}, "")
key := strings.Join([]string{url.ColonSeparatedKey(), constant.ConditionRouterRuleSuffix}, "")
dynamicConfiguration.AddListener(key, s)
value, err := dynamicConfiguration.GetRule(key)
if err != nil {
Expand Down
34 changes: 26 additions & 8 deletions cluster/router/tag/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,39 @@ func requestTag(invokers []protocol.Invoker, url *common.URL, invocation protoco
var (
addresses []string
result []protocol.Invoker
match []common.ParamMatch
)
for _, tagCfg := range cfg.Tags {
if tagCfg.Name == tag {
addresses = tagCfg.Addresses
match = tagCfg.Match
}
}
if len(addresses) == 0 {
// filter tag does not match
result = filterInvokers(invokers, tag, func(invoker protocol.Invoker, tag interface{}) bool {
return invoker.GetURL().GetParam(constant.Tagkey, "") != tag

// only one of 'match' and 'addresses' will take effect if both are specified.
if len(match) != 0 {
result = filterInvokers(invokers, match, func(invoker protocol.Invoker, match interface{}) bool {
matches := match.([]common.ParamMatch)
isMatch := true
for _, m := range matches {
if !m.IsMatch(invoker.GetURL()) {
isMatch = false
}
}
return !isMatch
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
})
logger.Debugf("[tag router] filter dynamic tag, tag=%s, invokers=%+v", tag, result)
} else {
// filter address does not match
result = filterInvokers(invokers, addresses, getAddressPredicate(false))
logger.Debugf("[tag router] filter dynamic tag address, invokers=%+v", result)
if len(addresses) == 0 {
// filter tag does not match
result = filterInvokers(invokers, tag, func(invoker protocol.Invoker, tag interface{}) bool {
return invoker.GetURL().GetParam(constant.Tagkey, "") != tag
})
logger.Debugf("[tag router] filter dynamic tag, tag=%s, invokers=%+v", tag, result)
} else {
// filter address does not match
result = filterInvokers(invokers, addresses, getAddressPredicate(false))
logger.Debugf("[tag router] filter dynamic tag address, invokers=%+v", result)
}
}
// returns the result directly
if *cfg.Force || requestIsForce(url, invocation) {
Expand All @@ -135,6 +152,7 @@ func requestTag(invokers []protocol.Invoker, url *common.URL, invocation protoco
return result
}

// filterInvokers remove invokers that match with predicate from the original input.
func filterInvokers(invokers []protocol.Invoker, param interface{}, predicate predicate) []protocol.Invoker {
result := make([]protocol.Invoker, len(invokers))
copy(result, invokers)
Expand Down
5 changes: 5 additions & 0 deletions common/constant/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ const (
const (
NonImportErrorMsgFormat = "Cluster for %s is not existing, make sure you have import the package."
)

const (
MatchCondition = "MATCH_CONDITION"
ApiVersion = "v3.0"
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
)
26 changes: 26 additions & 0 deletions common/host_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package common
import (
"os"
"strconv"
"strings"
)

import (
Expand Down Expand Up @@ -78,3 +79,28 @@ func isValidPort(port string) bool {
portInt, err := strconv.Atoi(port)
return err == nil && portInt > 0 && portInt < 65536
}

func IsMatchGlobPattern(pattern, value string) bool {
if constant.AnyValue == pattern {
return true
}
if pattern == "" && value == "" {
return true
}
if pattern == "" || value == "" {
return false
}

i := strings.Index(pattern, constant.AnyValue)
if i == -1 { // doesn't find "*"
return value == pattern
} else if i == len(pattern)-1 { // "*" is at the end
return strings.HasPrefix(value, pattern[0:i])
} else if i == 0 { // "*" is at the beginning
return strings.HasSuffix(value, pattern[i+1:])
} else { // "*" is in the middle
prefix := pattern[0:i]
suffix := pattern[i+1:]
return strings.HasPrefix(value, prefix) && strings.HasSuffix(value, suffix)
}
}
102 changes: 102 additions & 0 deletions common/match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package common

import (
"dubbo.apache.org/dubbo-go/v3/common/constant"
"fmt"
"net"
"regexp"
"strings"
)

type ParamMatch struct {
Key string `yaml:"key" json:"key,omitempty" property:"key"`
Value StringMatch `yaml:"value" json:"value,omitempty" property:"value"`
}

func (p ParamMatch) IsMatch(url *URL) bool {
return p.Value.IsMatch(url.GetParam(p.Key, ""))
}
chickenlj marked this conversation as resolved.
Show resolved Hide resolved

type StringMatch struct {
Exact string `yaml:"exact" json:"exact,omitempty" property:"exact"`
Prefix string `yaml:"prefix" json:"prefix,omitempty" property:"prefix"`
Regex string `yaml:"regex" json:"regex,omitempty" property:"regex"`
Noempty string `yaml:"noempty" json:"noempty,omitempty" property:"noempty"`
Empty string `yaml:"empty" json:"empty,omitempty" property:"empty"`
Wildcard string `yaml:"wildcard" json:"wildcard,omitempty" property:"wildcard"`
}

func (p StringMatch) IsMatch(value string) bool {
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
if p.Exact != "" {
return p.Exact == value
} else if p.Prefix != "" {
return strings.HasPrefix(value, p.Prefix)
} else if p.Regex != "" {
match, _ := regexp.MatchString(p.Regex, value)
return match
} else if p.Wildcard != "" {
return value == p.Wildcard || constant.AnyValue == p.Wildcard
} else if p.Empty != "" {
return value == ""
} else if p.Noempty != "" {
return value != ""
}
return false
}

type AddressMatch struct {
Wildcard string `yaml:"wildcard" json:"wildcard,omitempty" property:"wildcard"`
Cird string `yaml:"cird" json:"cird,omitempty" property:"cird"`
Exact string `yaml:"exact" json:"exact,omitempty" property:"exact"`
}

func (p AddressMatch) IsMatch(value string) bool {
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
if p.Cird != "" && value != "" {
_, ipnet, err := net.ParseCIDR(p.Cird)
if err != nil {
fmt.Println("Error", p.Cird, err)
return false
}
return ipnet.Contains(net.ParseIP(value))
}
if p.Wildcard != "" && value != "" {
if constant.AnyValue == value || constant.AnyHostValue == value {
return true
}
return IsMatchGlobPattern(p.Wildcard, value)
}
if p.Exact != "" && value != "" {
return p.Exact == value
}
return false
}

type ListStringMatch struct {
Oneof []StringMatch `yaml:"oneof" json:"oneof,omitempty" property:"oneof"`
}

func (p ListStringMatch) IsMatch(value string) bool {
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
for _, match := range p.Oneof {
if match.IsMatch(value) {
return true
}
}
return false
}
14 changes: 13 additions & 1 deletion common/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,19 @@ type URL struct {
Password string
Methods []string
// special for registry
SubURL *URL
SubURL *URL
Attributes sync.Map `json:"-" hessian:"-"`
}

func (c *URL) AddAttribute(key string, value interface{}) {
if value != nil {
c.Attributes.Store(key, value)
}
}

func (c *URL) GetAttribute(key string) interface{} {
v, _ := c.Attributes.Load(key)
return v
}

// JavaClassName POJO for URL
Expand Down
6 changes: 4 additions & 2 deletions config/router_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package config

import (
"dubbo.apache.org/dubbo-go/v3/common"
"github.com/creasty/defaults"
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
)

Expand All @@ -41,8 +42,9 @@ type RouterConfig struct {
}

type Tag struct {
Name string `yaml:"name" json:"name,omitempty" property:"name"`
Addresses []string `yaml:"addresses" json:"addresses,omitempty" property:"addresses"`
Name string `yaml:"name" json:"name,omitempty" property:"name"`
Match []common.ParamMatch `yaml:"match" json:"match,omitempty" property:"match"`
Addresses []string `yaml:"addresses" json:"addresses,omitempty" property:"addresses"`
}

// Prefix dubbo.router
Expand Down
89 changes: 57 additions & 32 deletions config_center/configurator/override.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package configurator

import (
"dubbo.apache.org/dubbo-go/v3/config_center/parser"
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
"strings"
)

Expand Down Expand Up @@ -57,34 +58,63 @@ func (c *overrideConfigurator) Configure(url *common.URL) {
// branch for version 2.7.x
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
apiVersion := c.configuratorUrl.GetParam(constant.ConfigVersionKey, "")
if len(apiVersion) != 0 {
var host string
currentSide := url.GetParam(constant.SideKey, "")
configuratorSide := c.configuratorUrl.GetParam(constant.SideKey, "")
if currentSide == configuratorSide && common.DubboRole[common.CONSUMER] == currentSide && c.configuratorUrl.Port == "0" {
localIP := common.GetLocalIp()
c.configureIfMatch(localIP, url)
} else if currentSide == configuratorSide && common.DubboRole[common.PROVIDER] == currentSide && c.configuratorUrl.Port == url.Port {
c.configureIfMatch(url.Ip, url)
if currentSide == configuratorSide && common.DubboRole[common.CONSUMER] == currentSide {
host = common.GetLocalIp()
} else if currentSide == configuratorSide && common.DubboRole[common.PROVIDER] == currentSide {
host = url.Ip
}

if strings.HasPrefix(apiVersion, constant.ApiVersion) {
c.configureIfMatchV3(host, url)
} else {
c.configureIfMatch(host, url)
}
} else {
// branch for version 2.6.x and less
c.configureDeprecated(url)
}
}

// configureIfMatch
func (c *overrideConfigurator) configureIfMatchV3(host string, url *common.URL) {
conditionKeys := getConditionKeys()
matcher := c.configuratorUrl.GetAttribute(constant.MatchCondition)
if matcher != nil {
conditionMatcher := matcher.(parser.ConditionMatch)
chickenlj marked this conversation as resolved.
Show resolved Hide resolved
if conditionMatcher.IsMatch(host, url) {
configUrl := c.configuratorUrl.CloneExceptParams(conditionKeys)
url.SetParams(configUrl.GetParams())
}
}
}

func (c *overrideConfigurator) configureDeprecated(url *common.URL) {
// If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
if c.configuratorUrl.Port != "0" {
if url.Port == c.configuratorUrl.Port {
c.configureIfMatch(url.Ip, url)
}
} else {
// override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0
// 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore;
// 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider
if url.GetParam(constant.SideKey, "") == common.DubboRole[common.CONSUMER] {
localIP := common.GetLocalIp()
c.configureIfMatch(localIP, url)
} else {
c.configureIfMatch(constant.AnyHostValue, url)
}
}
}

func (c *overrideConfigurator) configureIfMatchInternal(url *common.URL) {
configApp := c.configuratorUrl.GetParam(constant.ApplicationKey, c.configuratorUrl.Username)
currentApp := url.GetParam(constant.ApplicationKey, url.Username)
if len(configApp) == 0 || constant.AnyValue == configApp || configApp == currentApp {
conditionKeys := gxset.NewSet()
conditionKeys.Add(constant.CategoryKey)
conditionKeys.Add(constant.CheckKey)
conditionKeys.Add(constant.EnabledKey)
conditionKeys.Add(constant.GroupKey)
conditionKeys.Add(constant.VersionKey)
conditionKeys.Add(constant.ApplicationKey)
conditionKeys.Add(constant.SideKey)
conditionKeys.Add(constant.ConfigVersionKey)
conditionKeys.Add(constant.CompatibleConfigKey)
conditionKeys := getConditionKeys()
returnUrl := false
c.configuratorUrl.RangeParams(func(k, _ string) bool {
value := c.configuratorUrl.GetParam(k, "")
Expand Down Expand Up @@ -115,21 +145,16 @@ func (c *overrideConfigurator) configureIfMatch(host string, url *common.URL) {
}
}

func (c *overrideConfigurator) configureDeprecated(url *common.URL) {
// If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
if c.configuratorUrl.Port != "0" {
if url.Port == c.configuratorUrl.Port {
c.configureIfMatch(url.Ip, url)
}
} else {
// override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0
// 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore;
// 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider
if url.GetParam(constant.SideKey, "") == common.DubboRole[common.CONSUMER] {
localIP := common.GetLocalIp()
c.configureIfMatch(localIP, url)
} else {
c.configureIfMatch(constant.AnyHostValue, url)
}
}
func getConditionKeys() *gxset.HashSet {
conditionKeys := gxset.NewSet()
conditionKeys.Add(constant.CategoryKey)
conditionKeys.Add(constant.CheckKey)
conditionKeys.Add(constant.EnabledKey)
conditionKeys.Add(constant.GroupKey)
conditionKeys.Add(constant.VersionKey)
conditionKeys.Add(constant.ApplicationKey)
conditionKeys.Add(constant.SideKey)
conditionKeys.Add(constant.ConfigVersionKey)
conditionKeys.Add(constant.CompatibleConfigKey)
return conditionKeys
}
2 changes: 1 addition & 1 deletion config_center/mock_dynamic_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func (c *MockDynamicConfiguration) MockServiceConfigEvent() {
},
}
value, _ := yaml.Marshal(config)
key := "group*" + mockServiceName + ":1.0.0" + constant.ConfiguratorSuffix
key := mockServiceName + ":1.0.0:group" + constant.ConfiguratorSuffix
c.listener[key].Process(&ConfigChangeEvent{Key: key, Value: string(value), ConfigType: remoting.EventTypeAdd})
}

Expand Down
Loading
Loading