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

Ftr: Feature/application and service level router #662

Merged
35 changes: 28 additions & 7 deletions cluster/directory/base_directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,21 @@ func (dir *BaseDirectory) SetRouters(urls []*common.URL) {
for _, url := range urls {
routerKey := url.GetParam(constant.ROUTER_KEY, "")

if len(routerKey) > 0 {
factory := extension.GetRouterFactory(url.Protocol)
r, err := factory.NewPriorityRouter(url)
if err != nil {
logger.Errorf("Create router fail. router key: %s, url:%s, error: %+v", routerKey, url.Service(), err)
return
if len(routerKey) == 0 {
continue
}
if url.Protocol == constant.CONDITION_ROUTE_PROTOCOL {
if !dir.isProperRouter(url) {
continue
}
routers = append(routers, r)
}
factory := extension.GetRouterFactory(url.Protocol)
r, err := factory.NewPriorityRouter(url)
if err != nil {
logger.Errorf("Create router fail. router key: %s, url:%s, error: %+v", routerKey, url.Service(), err)
return
}
routers = append(routers, r)
}

logger.Infof("Init file condition router success, size: %v", len(routers))
Expand All @@ -104,6 +110,21 @@ func (dir *BaseDirectory) SetRouters(urls []*common.URL) {
rc.AddRouters(routers)
}

func (dir *BaseDirectory) isProperRouter(url *common.URL) bool {
app := url.GetParam(constant.APPLICATION_KEY, "")
serviceKey := dir.GetUrl().ServiceKey()
if serviceKey == "" {
serviceKey = dir.GetUrl().SubURL.ServiceKey()
}
if len(app) > 0 && app != dir.GetUrl().GetParam(constant.APPLICATION_KEY, "") {
return false
}
if url.ServiceKey() != serviceKey {
return false
}
return true
}

pantianying marked this conversation as resolved.
Show resolved Hide resolved
// Destroy Destroy
func (dir *BaseDirectory) Destroy(doDestroy func()) {
if dir.destroyed.CAS(false, true) {
Expand Down
12 changes: 8 additions & 4 deletions cluster/directory/base_directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ func TestNewBaseDirectory(t *testing.T) {
}

func TestBuildRouterChain(t *testing.T) {
directory := NewBaseDirectory(&url)

regURL := url
regURL.AddParam(constant.INTERFACE_KEY, "mock-app")
directory := NewBaseDirectory(&regURL)

assert.NotNil(t, directory)

localIP, _ := gxnet.GetLocalIP()
rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
routeURL := getRouteUrl(rule)
routeURL := getRouteURL(rule)
routeURL.AddParam(constant.INTERFACE_KEY, "mock-app")
routerURLs := make([]*common.URL, 0)
routerURLs = append(routerURLs, routeURL)
directory.SetRouters(routerURLs)
Expand All @@ -63,9 +67,9 @@ func TestBuildRouterChain(t *testing.T) {
assert.NotNil(t, chain)
}

func getRouteUrl(rule string) *common.URL {
func getRouteURL(rule string) *common.URL {
anyUrl.AddParam("rule", rule)
anyUrl.AddParam("force", "true")
anyUrl.AddParam(constant.ROUTER_KEY, "router")
return &url
return &anyUrl
}
16 changes: 11 additions & 5 deletions cluster/router/chain/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ func TestNewRouterChain(t *testing.T) {
err = z.Create(path)
assert.NoError(t, err)

testyml := `enabled: true
testyml := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand All @@ -93,15 +95,15 @@ conditions:
assert.NotNil(t, appRouter)
assert.NotNil(t, appRouter.RouterRule())
rule := appRouter.RouterRule()
assert.Equal(t, "", rule.Scope)
assert.Equal(t, "application", rule.Scope)
assert.True(t, rule.Force)
assert.True(t, rule.Enabled)
assert.True(t, rule.Valid)

assert.Equal(t, testyml, rule.RawRule)
assert.Equal(t, false, rule.Runtime)
assert.Equal(t, false, rule.Dynamic)
assert.Equal(t, "", rule.Key)
assert.Equal(t, "mock-app", rule.Key)
}

func TestNewRouterChainURLNil(t *testing.T) {
Expand All @@ -116,7 +118,9 @@ func TestRouterChainAddRouters(t *testing.T) {
err = z.Create(path)
assert.NoError(t, err)

testyml := `enabled: true
testyml := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand Down Expand Up @@ -182,7 +186,9 @@ func TestRouterChainRouteAppRouter(t *testing.T) {
err = z.Create(path)
assert.NoError(t, err)

testyml := `enabled: true
testyml := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand Down
19 changes: 13 additions & 6 deletions cluster/router/condition/app_router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ var (

func TestNewAppRouter(t *testing.T) {

testYML := `enabled: true
testYML := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand Down Expand Up @@ -83,21 +85,23 @@ conditions:
assert.NotNil(t, appRouter)
assert.NotNil(t, appRouter.RouterRule())
rule := appRouter.RouterRule()
assert.Equal(t, "", rule.Scope)
assert.Equal(t, "application", rule.Scope)
assert.True(t, rule.Force)
assert.True(t, rule.Enabled)
assert.True(t, rule.Valid)

assert.Equal(t, testYML, rule.RawRule)
assert.Equal(t, false, rule.Runtime)
assert.Equal(t, false, rule.Dynamic)
assert.Equal(t, "", rule.Key)
assert.Equal(t, "mock-app", rule.Key)
assert.Equal(t, 0, rule.Priority)
}

func TestGenerateConditions(t *testing.T) {

testYML := `enabled: true
testYML := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand Down Expand Up @@ -135,7 +139,9 @@ conditions:

func TestProcess(t *testing.T) {

testYML := `enabled: true
testYML := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
conditions:
Expand Down Expand Up @@ -165,7 +171,8 @@ conditions:

assert.Equal(t, 1, len(appRouter.conditionRouters))

testNewYML := `
testNewYML := `scope: application
key: mock-app
enabled: true
force: true
runtime: false
Expand Down
39 changes: 38 additions & 1 deletion cluster/router/condition/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package condition
import (
"encoding/base64"
"net/url"
"regexp"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -71,11 +72,47 @@ func (f *FileConditionRouter) URL() common.URL {
common.WithParamsValue(constant.RouterPriority, strconv.Itoa(routerRule.Priority)),
common.WithParamsValue(constant.RULE_KEY, base64.URLEncoding.EncodeToString([]byte(rule))),
common.WithParamsValue(constant.ROUTER_KEY, constant.CONDITION_ROUTE_PROTOCOL),
common.WithParamsValue(constant.CATEGORY_KEY, constant.ROUTERS_CATEGORY))
common.WithParamsValue(constant.CATEGORY_KEY, constant.ROUTERS_CATEGORY),
)
if routerRule.Scope == constant.RouterApplicationScope {
f.url.AddParam(constant.APPLICATION_KEY, routerRule.Key)
return
}
grp, srv, ver, e := parseServiceRouterKey(routerRule.Key)
if e != nil {
return
}
if len(grp) > 0 {
f.url.AddParam(constant.GROUP_KEY, grp)
}
if len(ver) > 0 {
f.url.AddParam(constant.VERSION_KEY, ver)
}
if len(srv) > 0 {
f.url.AddParam(constant.INTERFACE_KEY, srv)
}
})
return f.url
}

func parseServiceRouterKey(key string) (string, string, string, error) {
pantianying marked this conversation as resolved.
Show resolved Hide resolved
if len(strings.TrimSpace(key)) == 0 {
return "", "", "", nil
}
reg := regexp.MustCompile(`(.*/{1})?([^:/]+)(:{1}[^:]*)?`)
strs := reg.FindAllStringSubmatch(key, -1)
if strs == nil || len(strs) > 1 {
return "", "", "", perrors.Errorf("Invalid key, service key must follow [{group}/]{service}[:{version}] pattern")
}
if len(strs[0]) != 4 {
return "", "", "", perrors.Errorf("Parse service router key failed")
}
grp := strings.TrimSpace(strings.TrimRight(strs[0][1], "/"))
srv := strings.TrimSpace(strs[0][2])
ver := strings.TrimSpace(strings.TrimLeft(strs[0][3], ":"))
zouyx marked this conversation as resolved.
Show resolved Hide resolved
return grp, srv, ver, nil
}

func parseCondition(conditions []string) string {
var when, then string
for _, condition := range conditions {
Expand Down
74 changes: 71 additions & 3 deletions cluster/router/condition/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import (
)

func TestLoadYmlConfig(t *testing.T) {
router, e := NewFileConditionRouter([]byte(`priority: 1
router, e := NewFileConditionRouter([]byte(`scope: application
key: mock-app
priority: 1
force: true
conditions :
- "a => b"
Expand All @@ -47,12 +49,78 @@ func TestParseCondition(t *testing.T) {
}

func TestFileRouterURL(t *testing.T) {
router, e := NewFileConditionRouter([]byte(`priority: 1
router, e := NewFileConditionRouter([]byte(`scope: application
key: mock-app
priority: 1
force: true
conditions :
- "a => b"
- "c => d"`))
assert.Nil(t, e)
assert.NotNil(t, router)
assert.Equal(t, "condition://0.0.0.0:?category=routers&force=true&priority=1&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D", router.URL().String())
assert.Equal(t, "condition://0.0.0.0:?application=mock-app&category=routers&force=true&priority=1&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D", router.URL().String())

router, e = NewFileConditionRouter([]byte(`scope: service
key: mock-service
priority: 1
force: true
conditions :
- "a => b"
- "c => d"`))
assert.Nil(t, e)
assert.NotNil(t, router)
assert.Equal(t, "condition://0.0.0.0:?category=routers&force=true&interface=mock-service&priority=1&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D", router.URL().String())

router, e = NewFileConditionRouter([]byte(`scope: service
key: grp1/mock-service:v1
priority: 1
force: true
conditions :
- "a => b"
- "c => d"`))
assert.Nil(t, e)
assert.NotNil(t, router)
assert.Equal(t, "condition://0.0.0.0:?category=routers&force=true&group=grp1&interface=mock-service&priority=1&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D&version=v1", router.URL().String())
}

func TestParseServiceRouterKey(t *testing.T) {
testString := " mock-group / mock-service:1.0.0"
grp, srv, ver, err := parseServiceRouterKey(testString)
assert.Equal(t, "mock-group", grp)
assert.Equal(t, "mock-service", srv)
assert.Equal(t, "1.0.0", ver)

testString = "mock-group/mock-service"
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Equal(t, "mock-group", grp)
assert.Equal(t, "mock-service", srv)
assert.Equal(t, "", ver)

testString = "mock-service:1.0.0"
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Equal(t, "", grp)
assert.Equal(t, "mock-service", srv)
assert.Equal(t, "1.0.0", ver)

testString = "mock-service"
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Equal(t, "", grp)
assert.Equal(t, "mock-service", srv)
assert.Equal(t, "", ver)

testString = "/mock-service:"
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Equal(t, "", grp)
assert.Equal(t, "mock-service", srv)
assert.Equal(t, "", ver)

testString = "grp:mock-service:123"
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Error(t, err)

testString = ""
grp, srv, ver, err = parseServiceRouterKey(testString)
assert.Equal(t, "", grp)
assert.Equal(t, "", srv)
assert.Equal(t, "", ver)
}
8 changes: 7 additions & 1 deletion cluster/router/condition/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,13 @@ func NewConditionRouter(url *common.URL) (*ConditionRouter, error) {
}

router.url = url
router.priority = url.GetParamInt(constant.RouterPriority, 0)
var defaultPriority int64 = 0
if url.GetParam(constant.APPLICATION_KEY, "") != "" {
defaultPriority = 150
} else if url.GetParam(constant.INTERFACE_KEY, "") != "" {
defaultPriority = 140
williamfeng323 marked this conversation as resolved.
Show resolved Hide resolved
}
router.priority = url.GetParamInt(constant.RouterPriority, defaultPriority)
router.Force = url.GetParamBool(constant.RouterForce, false)
router.enabled = url.GetParamBool(constant.RouterEnabled, true)

Expand Down
5 changes: 3 additions & 2 deletions cluster/router/condition/router_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ import (
import (
"github.com/apache/dubbo-go/cluster/router"
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/yaml"
)

// RouterRule RouterRule config read from config file or config center
type RouterRule struct {
router.BaseRouterRule `yaml:",inline""`
router.BaseRouterRule `yaml:",inline"`
Conditions []string
}

Expand All @@ -57,7 +58,7 @@ func getRule(rawRule string) (*RouterRule, error) {
return r, err
}
r.RawRule = rawRule
if len(r.Conditions) != 0 {
if len(r.Conditions) > 0 && len(r.Key) > 0 && (r.Scope == constant.RouterApplicationScope || r.Scope == constant.RouterServiceScope) {
r.Valid = true
}

Expand Down
Loading