Skip to content

Commit

Permalink
Merge pull request #662 from williamfeng323/feature/application-level…
Browse files Browse the repository at this point in the history
…-router

Ftr: Feature/application and service level router
  • Loading branch information
pantianying authored Aug 9, 2020
2 parents 613cc6e + 5f02d53 commit 2aafdeb
Show file tree
Hide file tree
Showing 20 changed files with 429 additions and 55 deletions.
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 true
}
if url.ServiceKey() == serviceKey {
return true
}
return false
}

// Destroy Destroy
func (dir *BaseDirectory) Destroy(doDestroy func()) {
if dir.destroyed.CAS(false, true) {
Expand Down
64 changes: 56 additions & 8 deletions cluster/directory/base_directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
var (
url, _ = common.NewURL(
fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
anyUrl, _ = common.NewURL(fmt.Sprintf("condition://%s/com.foo.BarService", constant.ANYHOST_VALUE))
anyURL, _ = common.NewURL(fmt.Sprintf("condition://%s/com.foo.BarService", constant.ANYHOST_VALUE))
)

func TestNewBaseDirectory(t *testing.T) {
Expand All @@ -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, anyURL)
routeURL.AddParam(constant.INTERFACE_KEY, "mock-app")
routerURLs := make([]*common.URL, 0)
routerURLs = append(routerURLs, routeURL)
directory.SetRouters(routerURLs)
Expand All @@ -63,9 +67,53 @@ func TestBuildRouterChain(t *testing.T) {
assert.NotNil(t, chain)
}

func getRouteUrl(rule string) *common.URL {
anyUrl.AddParam("rule", rule)
anyUrl.AddParam("force", "true")
anyUrl.AddParam(constant.ROUTER_KEY, "router")
return &url
func getRouteURL(rule string, u common.URL) *common.URL {
ru := u
ru.AddParam("rule", rule)
ru.AddParam("force", "true")
ru.AddParam(constant.ROUTER_KEY, "router")
return &ru
}

func TestIsProperRouter(t *testing.T) {
regURL := url
regURL.AddParam(constant.APPLICATION_KEY, "mock-app")
d := NewBaseDirectory(&regURL)
localIP, _ := gxnet.GetLocalIP()
rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
routeURL := getRouteURL(rule, anyURL)
routeURL.AddParam(constant.APPLICATION_KEY, "mock-app")
rst := d.isProperRouter(routeURL)
assert.True(t, rst)

regURL.AddParam(constant.APPLICATION_KEY, "")
regURL.AddParam(constant.INTERFACE_KEY, "com.foo.BarService")
d = NewBaseDirectory(&regURL)
routeURL = getRouteURL(rule, anyURL)
routeURL.AddParam(constant.INTERFACE_KEY, "com.foo.BarService")
rst = d.isProperRouter(routeURL)
assert.True(t, rst)

regURL.AddParam(constant.APPLICATION_KEY, "")
regURL.AddParam(constant.INTERFACE_KEY, "")
d = NewBaseDirectory(&regURL)
routeURL = getRouteURL(rule, anyURL)
rst = d.isProperRouter(routeURL)
assert.True(t, rst)

regURL.SetParam(constant.APPLICATION_KEY, "")
regURL.SetParam(constant.INTERFACE_KEY, "")
d = NewBaseDirectory(&regURL)
routeURL = getRouteURL(rule, anyURL)
routeURL.AddParam(constant.APPLICATION_KEY, "mock-service")
rst = d.isProperRouter(routeURL)
assert.False(t, rst)

regURL.SetParam(constant.APPLICATION_KEY, "")
regURL.SetParam(constant.INTERFACE_KEY, "")
d = NewBaseDirectory(&regURL)
routeURL = getRouteURL(rule, anyURL)
routeURL.AddParam(constant.INTERFACE_KEY, "mock-service")
rst = d.isProperRouter(routeURL)
assert.False(t, rst)
}
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
45 changes: 44 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,53 @@ 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
}

// The input value must follow [{group}/]{service}[:{version}] pattern
// the returning strings are representing group, service, version respectively.
// input: mock-group/mock-service:1.0.0 ==> "mock-group", "mock-service", "1.0.0"
// input: mock-group/mock-service ==> "mock-group", "mock-service", ""
// input: mock-service:1.0.0 ==> "", "mock-service", "1.0.0"
// For more samples, please refer to unit test.
func parseServiceRouterKey(key string) (string, string, string, error) {
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], ":"))
return grp, srv, ver, nil
}

func parseCondition(conditions []string) string {
var when, then string
for _, condition := range conditions {
Expand Down
Loading

0 comments on commit 2aafdeb

Please sign in to comment.