You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/05/08 13:15:05 UTC
[dubbo-go] branch 3.0 updated: Feat: add v3router to dubbogo (#1187)
This is an automated email from the ASF dual-hosted git repository.
alexstocks pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/3.0 by this push:
new 76d056e Feat: add v3router to dubbogo (#1187)
76d056e is described below
commit 76d056e7b1b36b20b8e9c76ee79b2d48d45c3a12
Author: Laurence <45...@users.noreply.github.com>
AuthorDate: Sat May 8 21:14:58 2021 +0800
Feat: add v3router to dubbogo (#1187)
* fix: add v3router
* fix: fix import block
* fix: code review
* fix
* fix: fix nil ptr bug
---
cluster/router/v3router/dubbo_rule.go | 61 +++++
cluster/router/v3router/factory.go | 35 +++
cluster/router/v3router/factory_test.go | 35 +++
.../v3router/judger/attachment_match_judger.go | 82 +++++++
.../judger/attachment_match_judger_test.go | 49 ++++
.../router/v3router/judger/bool_match_judger.go | 37 +++
.../v3router/judger/bool_match_judger_test.go | 48 ++++
.../router/v3router/judger/double_match_judger.go | 49 ++++
.../v3router/judger/double_match_judger_test.go | 61 +++++
.../v3router/judger/double_range_match_judger.go | 39 ++++
.../judger/double_range_match_judger_test.go | 47 ++++
.../v3router/judger/list_double_match_judger.go | 44 ++++
.../judger/list_double_match_judger_test.go | 100 ++++++++
.../v3router/judger/list_string_match_judger.go | 44 ++++
.../router/v3router/judger/method_match_judger.go | 89 +++++++
.../router/v3router/judger/string_match_judger.go | 60 +++++
.../v3router/judger/string_match_judger_test.go | 56 +++++
.../v3router/judger/url_label_match_judge.go | 32 +++
cluster/router/v3router/k8s_api/k8s.go | 41 ++++
.../v3router/k8s_api/listener_handler_impl.go | 198 ++++++++++++++++
cluster/router/v3router/k8s_crd/client.go | 134 +++++++++++
.../v3router/k8s_crd/deploy/unifom_router_crd.yml | 43 ++++
.../router/v3router/k8s_crd/listener_handler.go | 35 +++
cluster/router/v3router/router_chain.go | 246 ++++++++++++++++++++
cluster/router/v3router/router_chain_test.go | 208 +++++++++++++++++
cluster/router/v3router/test_file/dest_rule.yml | 17 ++
.../router/v3router/test_file/virtual_service.yml | 158 +++++++++++++
cluster/router/v3router/uniform_route.go | 67 ++++++
cluster/router/v3router/uniform_rule.go | 257 +++++++++++++++++++++
config/uniform_router_config.go | 231 ++++++++++++++++++
go.mod | 3 +-
go.sum | 7 +-
test/integrate/dubbo/go-client/go.sum | 2 +
test/integrate/dubbo/go-server/go.sum | 2 +
34 files changed, 2612 insertions(+), 5 deletions(-)
diff --git a/cluster/router/v3router/dubbo_rule.go b/cluster/router/v3router/dubbo_rule.go
new file mode 100644
index 0000000..a77a13e
--- /dev/null
+++ b/cluster/router/v3router/dubbo_rule.go
@@ -0,0 +1,61 @@
+/*
+ * 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 v3router
+
+import (
+ "github.com/apache/dubbo-go/common"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/protocol"
+)
+
+// nolint
+type DubboRouterRule struct {
+ uniformRules []*UniformRule
+}
+
+func newDubboRouterRule(dubboRoutes []*config.DubboRoute,
+ destinationMap map[string]map[string]string) (*DubboRouterRule, error) {
+
+ uniformRules := make([]*UniformRule, 0)
+ for _, v := range dubboRoutes {
+ uniformRule, err := newUniformRule(v, destinationMap)
+ if err != nil {
+ return nil, err
+ }
+ uniformRules = append(uniformRules, uniformRule)
+ }
+
+ return &DubboRouterRule{
+ uniformRules: uniformRules,
+ }, nil
+}
+
+func (drr *DubboRouterRule) route(invokers []protocol.Invoker, url *common.URL,
+ invocation protocol.Invocation) []protocol.Invoker {
+
+ resultInvokers := make([]protocol.Invoker, 0)
+ for _, v := range drr.uniformRules {
+ if resultInvokers = v.route(invokers, url, invocation); len(resultInvokers) == 0 {
+ continue
+ }
+ // once there is a uniformRule successfully get target invoker lists, return it
+ return resultInvokers
+ }
+ // return s empty invoker list
+ return resultInvokers
+}
diff --git a/cluster/router/v3router/factory.go b/cluster/router/v3router/factory.go
new file mode 100644
index 0000000..30b121c
--- /dev/null
+++ b/cluster/router/v3router/factory.go
@@ -0,0 +1,35 @@
+/*
+ * 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 v3router
+
+import (
+ "github.com/apache/dubbo-go/cluster/router"
+)
+
+// UniformRouteFactory is uniform router's factory
+type UniformRouteFactory struct{}
+
+// NewUniformRouterFactory constructs a new PriorityRouterFactory
+func NewUniformRouterFactory() router.PriorityRouterFactory {
+ return &UniformRouteFactory{}
+}
+
+// NewPriorityRouter construct a new UniformRouteFactory as PriorityRouter
+func (f *UniformRouteFactory) NewPriorityRouter(vsConfigBytes, distConfigBytes []byte, notify chan struct{}) (router.PriorityRouter, error) {
+ return NewUniformRouterChain(vsConfigBytes, distConfigBytes, notify)
+}
diff --git a/cluster/router/v3router/factory_test.go b/cluster/router/v3router/factory_test.go
new file mode 100644
index 0000000..365d755
--- /dev/null
+++ b/cluster/router/v3router/factory_test.go
@@ -0,0 +1,35 @@
+/*
+ * 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 v3router
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+// TestUniformRouterFacotry created a new factory that can new uniform router
+func TestUniformRouterFacotry(t *testing.T) {
+ factory := NewUniformRouterFactory()
+ assert.NotNil(t, factory)
+ router, err := factory.NewPriorityRouter([]byte{}, []byte{}, make(chan struct{}))
+ assert.Nil(t, err)
+ assert.NotNil(t, router)
+}
diff --git a/cluster/router/v3router/judger/attachment_match_judger.go b/cluster/router/v3router/judger/attachment_match_judger.go
new file mode 100644
index 0000000..7772a2d
--- /dev/null
+++ b/cluster/router/v3router/judger/attachment_match_judger.go
@@ -0,0 +1,82 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/protocol"
+)
+
+type AttachmentMatchJudger struct {
+ config.DubboAttachmentMatch
+}
+
+// nolint
+func (amj *AttachmentMatchJudger) Judge(invocation protocol.Invocation) bool {
+ invAttaMap := invocation.Attachments()
+ if amj.EagleeyeContext != nil {
+ for k, v := range amj.EagleeyeContext {
+ invAttaValue, ok := invAttaMap[k]
+ if !ok {
+ if v.Empty == "" {
+ return false
+ }
+ continue
+ }
+ // exist this key
+ str, ok := invAttaValue.(string)
+ if !ok {
+ return false
+ }
+ strJudger := NewStringMatchJudger(v)
+ if !strJudger.Judge(str) {
+ return false
+ }
+ }
+ }
+
+ if amj.DubboContext != nil {
+ for k, v := range amj.DubboContext {
+ invAttaValue, ok := invAttaMap[k]
+ if !ok {
+ if v.Empty == "" {
+ return false
+ }
+ continue
+ }
+ // exist this key
+ str, ok := invAttaValue.(string)
+ if !ok {
+ return false
+ }
+ strJudger := NewStringMatchJudger(v)
+ if !strJudger.Judge(str) {
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+// nolint
+func NewAttachmentMatchJudger(matchConf *config.DubboAttachmentMatch) *AttachmentMatchJudger {
+ return &AttachmentMatchJudger{
+ DubboAttachmentMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/attachment_match_judger_test.go b/cluster/router/v3router/judger/attachment_match_judger_test.go
new file mode 100644
index 0000000..47dae98
--- /dev/null
+++ b/cluster/router/v3router/judger/attachment_match_judger_test.go
@@ -0,0 +1,49 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestAttachmentMatchJudger(t *testing.T) {
+ dubboCtxMap := make(map[string]*config.StringMatch)
+ dubboIvkMap := make(map[string]interface{})
+ dubboCtxMap["test-key"] = &config.StringMatch{
+ Exact: "abc",
+ }
+ dubboIvkMap["test-key"] = "abc"
+ assert.True(t, NewAttachmentMatchJudger(&config.DubboAttachmentMatch{
+ DubboContext: dubboCtxMap,
+ }).Judge(invocation.NewRPCInvocation("method", nil, dubboIvkMap)))
+
+ dubboIvkMap["test-key"] = "abd"
+ assert.False(t, NewAttachmentMatchJudger(&config.DubboAttachmentMatch{
+ DubboContext: dubboCtxMap,
+ }).Judge(invocation.NewRPCInvocation("method", nil, dubboIvkMap)))
+
+}
diff --git a/cluster/router/v3router/judger/bool_match_judger.go b/cluster/router/v3router/judger/bool_match_judger.go
new file mode 100644
index 0000000..da6bf8a
--- /dev/null
+++ b/cluster/router/v3router/judger/bool_match_judger.go
@@ -0,0 +1,37 @@
+/*
+ * 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 judger
+
+import "github.com/apache/dubbo-go/config"
+
+// nolint
+type BoolMatchJudger struct {
+ config.BoolMatch
+}
+
+// nolint
+func (lsmj *BoolMatchJudger) Judge(input bool) bool {
+ return input == lsmj.Exact
+}
+
+// nolint
+func newBoolMatchJudger(matchConf *config.BoolMatch) *BoolMatchJudger {
+ return &BoolMatchJudger{
+ BoolMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/bool_match_judger_test.go b/cluster/router/v3router/judger/bool_match_judger_test.go
new file mode 100644
index 0000000..1ed3e35
--- /dev/null
+++ b/cluster/router/v3router/judger/bool_match_judger_test.go
@@ -0,0 +1,48 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+func TestBoolMatchJudger(t *testing.T) {
+ assert.True(t, newBoolMatchJudger(&config.BoolMatch{
+ Exact: true,
+ }).Judge(true))
+
+ assert.True(t, newBoolMatchJudger(&config.BoolMatch{
+ Exact: false,
+ }).Judge(false))
+
+ assert.False(t, newBoolMatchJudger(&config.BoolMatch{
+ Exact: true,
+ }).Judge(false))
+
+ assert.False(t, newBoolMatchJudger(&config.BoolMatch{
+ Exact: false,
+ }).Judge(true))
+}
diff --git a/cluster/router/v3router/judger/double_match_judger.go b/cluster/router/v3router/judger/double_match_judger.go
new file mode 100644
index 0000000..b640d94
--- /dev/null
+++ b/cluster/router/v3router/judger/double_match_judger.go
@@ -0,0 +1,49 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+// nolint
+type DoubleMatchJudger struct {
+ config.DoubleMatch
+}
+
+// nolint
+func (dmj *DoubleMatchJudger) Judge(input float64) bool {
+ if dmj.Exact != 0 {
+ return input == dmj.Exact
+ }
+ if dmj.Range != nil {
+ return newDoubleRangeMatchJudger(dmj.Range).Judge(input)
+ }
+ // todo mod match ??
+ //if dmj.Mode != 0 {
+ //
+ //}
+ return true
+}
+
+// nolint
+func newDoubleMatchJudger(matchConf *config.DoubleMatch) *DoubleMatchJudger {
+ return &DoubleMatchJudger{
+ DoubleMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/double_match_judger_test.go b/cluster/router/v3router/judger/double_match_judger_test.go
new file mode 100644
index 0000000..4864b50
--- /dev/null
+++ b/cluster/router/v3router/judger/double_match_judger_test.go
@@ -0,0 +1,61 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+func TestDoubleMatchJudger(t *testing.T) {
+ assert.True(t, newDoubleMatchJudger(&config.DoubleMatch{
+ Exact: 3.14159,
+ }).Judge(3.14159))
+
+ assert.False(t, newDoubleMatchJudger(&config.DoubleMatch{
+ Exact: 3.14159,
+ }).Judge(3.14155927))
+
+ assert.True(t, newDoubleMatchJudger(&config.DoubleMatch{
+ Range: &config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ },
+ }).Judge(1.3))
+
+ assert.False(t, newDoubleMatchJudger(&config.DoubleMatch{
+ Range: &config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ },
+ }).Judge(1.9))
+
+ assert.False(t, newDoubleMatchJudger(&config.DoubleMatch{
+ Range: &config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ },
+ }).Judge(0.9))
+}
diff --git a/cluster/router/v3router/judger/double_range_match_judger.go b/cluster/router/v3router/judger/double_range_match_judger.go
new file mode 100644
index 0000000..3f3adc3
--- /dev/null
+++ b/cluster/router/v3router/judger/double_range_match_judger.go
@@ -0,0 +1,39 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+// nolint
+type DoubleRangeMatchJudger struct {
+ config.DoubleRangeMatch
+}
+
+// nolint
+func (drmj *DoubleRangeMatchJudger) Judge(input float64) bool {
+ return input >= drmj.Start && input < drmj.End
+}
+
+// nolint
+func newDoubleRangeMatchJudger(matchConf *config.DoubleRangeMatch) *DoubleRangeMatchJudger {
+ return &DoubleRangeMatchJudger{
+ DoubleRangeMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/double_range_match_judger_test.go b/cluster/router/v3router/judger/double_range_match_judger_test.go
new file mode 100644
index 0000000..4e1926d
--- /dev/null
+++ b/cluster/router/v3router/judger/double_range_match_judger_test.go
@@ -0,0 +1,47 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+func TestDoubleRangeMatchJudger(t *testing.T) {
+ assert.True(t, newDoubleRangeMatchJudger(&config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ }).Judge(1.3))
+
+ assert.False(t, newDoubleRangeMatchJudger(&config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ }).Judge(1.9))
+
+ assert.False(t, newDoubleRangeMatchJudger(&config.DoubleRangeMatch{
+ Start: 1.0,
+ End: 1.5,
+ }).Judge(0.9))
+}
diff --git a/cluster/router/v3router/judger/list_double_match_judger.go b/cluster/router/v3router/judger/list_double_match_judger.go
new file mode 100644
index 0000000..25feccd
--- /dev/null
+++ b/cluster/router/v3router/judger/list_double_match_judger.go
@@ -0,0 +1,44 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+// nolint
+type ListDoubleMatchJudger struct {
+ config.ListDoubleMatch
+}
+
+// nolint
+func (lsmj *ListDoubleMatchJudger) Judge(input float64) bool {
+ for _, v := range lsmj.Oneof {
+ if newDoubleMatchJudger(v).Judge(input) {
+ return true
+ }
+ }
+ return false
+}
+
+// nolint
+func newListDoubleMatchJudger(matchConf *config.ListDoubleMatch) *ListDoubleMatchJudger {
+ return &ListDoubleMatchJudger{
+ ListDoubleMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/list_double_match_judger_test.go b/cluster/router/v3router/judger/list_double_match_judger_test.go
new file mode 100644
index 0000000..66d884f
--- /dev/null
+++ b/cluster/router/v3router/judger/list_double_match_judger_test.go
@@ -0,0 +1,100 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+func TestListDoubleMatchJudger_Judge(t *testing.T) {
+ assert.True(t, newListDoubleMatchJudger(&config.ListDoubleMatch{
+ Oneof: []*config.DoubleMatch{
+ {
+ Exact: 3.14,
+ },
+ {
+ Range: &config.DoubleRangeMatch{
+ Start: 1.5,
+ End: 1.9,
+ },
+ },
+ {
+ Exact: 1.3,
+ },
+ },
+ }).Judge(1.3))
+
+ assert.False(t, newListDoubleMatchJudger(&config.ListDoubleMatch{
+ Oneof: []*config.DoubleMatch{
+ {
+ Exact: 3.14,
+ },
+ {
+ Range: &config.DoubleRangeMatch{
+ Start: 1.5,
+ End: 1.9,
+ },
+ },
+ {
+ Exact: 1.2,
+ },
+ },
+ }).Judge(1.3))
+
+ assert.True(t, newListDoubleMatchJudger(&config.ListDoubleMatch{
+ Oneof: []*config.DoubleMatch{
+ {
+ Exact: 3.14,
+ },
+ {
+ Range: &config.DoubleRangeMatch{
+ Start: 1.2,
+ End: 1.9,
+ },
+ },
+ {
+ Exact: 1.4,
+ },
+ },
+ }).Judge(1.3))
+
+ assert.False(t, newListDoubleMatchJudger(&config.ListDoubleMatch{
+ Oneof: []*config.DoubleMatch{
+ {
+ Exact: 3.14,
+ },
+ {
+ Range: &config.DoubleRangeMatch{
+ Start: 1.5,
+ End: 1.9,
+ },
+ },
+ {
+ Exact: 1.0,
+ },
+ },
+ }).Judge(1.3))
+}
diff --git a/cluster/router/v3router/judger/list_string_match_judger.go b/cluster/router/v3router/judger/list_string_match_judger.go
new file mode 100644
index 0000000..e4f7cb7
--- /dev/null
+++ b/cluster/router/v3router/judger/list_string_match_judger.go
@@ -0,0 +1,44 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+// nolint
+type ListStringMatchJudger struct {
+ config.ListStringMatch
+}
+
+// nolint
+func (lsmj *ListStringMatchJudger) Judge(input string) bool {
+ for _, v := range lsmj.Oneof {
+ if NewStringMatchJudger(v).Judge(input) {
+ return true
+ }
+ }
+ return false
+}
+
+// nolint
+func newListStringMatchJudger(matchConf *config.ListStringMatch) *ListStringMatchJudger {
+ return &ListStringMatchJudger{
+ ListStringMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/method_match_judger.go b/cluster/router/v3router/judger/method_match_judger.go
new file mode 100644
index 0000000..672a43a
--- /dev/null
+++ b/cluster/router/v3router/judger/method_match_judger.go
@@ -0,0 +1,89 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/protocol"
+)
+
+// nolint
+type MethodMatchJudger struct {
+ config.DubboMethodMatch
+}
+
+// Judge Method Match Judger only judge on
+func (mmj *MethodMatchJudger) Judge(invocation protocol.Invocation) bool {
+ if mmj.NameMatch != nil {
+ strJudger := NewStringMatchJudger(mmj.NameMatch)
+ if !strJudger.Judge(invocation.MethodName()) {
+ return false
+ }
+ }
+
+ // todo now argc Must not be zero, else it will cause unexpected result
+ if mmj.Argc != 0 && len(invocation.ParameterValues()) != mmj.Argc {
+ return false
+ }
+
+ if mmj.Args != nil {
+ params := invocation.ParameterValues()
+ for _, v := range mmj.Args {
+ index := int(v.Index)
+ if index > len(params) || index < 1 {
+ return false
+ }
+ value := params[index-1]
+ if value.Type().String() != v.Type {
+ return false
+ }
+ switch v.Type {
+ case "string":
+ if !newListStringMatchJudger(v.StrValue).Judge(value.String()) {
+ return false
+ }
+ case "float", "int":
+ // todo now numbers Must not be zero, else it will ignore this match
+ if !newListDoubleMatchJudger(v.NumValue).Judge(value.Float()) {
+ return false
+ }
+ case "bool":
+ if !newBoolMatchJudger(v.BoolValue).Judge(value.Bool()) {
+ return false
+ }
+ default:
+ }
+ }
+ }
+ // todo Argp match judge ??? conflict to args?
+ //if mmj.Argp != nil {
+ //
+ //}
+ // todo Headers match judge: reserve for triple
+ //if mmj.Headers != nil {
+ //
+ //}
+ return true
+}
+
+// nolint
+func NewMethodMatchJudger(matchConf *config.DubboMethodMatch) *MethodMatchJudger {
+ return &MethodMatchJudger{
+ DubboMethodMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/string_match_judger.go b/cluster/router/v3router/judger/string_match_judger.go
new file mode 100644
index 0000000..02b74b5
--- /dev/null
+++ b/cluster/router/v3router/judger/string_match_judger.go
@@ -0,0 +1,60 @@
+/*
+ * 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 judger
+
+import (
+ "regexp"
+ "strings"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+// nolint
+type StringMatchJudger struct {
+ config.StringMatch
+}
+
+// nolint
+func (smj *StringMatchJudger) Judge(input string) bool {
+ if smj.Exact != "" {
+ return input == smj.Exact
+ }
+ if smj.Prefix != "" {
+ return strings.HasPrefix(input, smj.Prefix)
+ }
+ if smj.Regex != "" {
+ ok, err := regexp.MatchString(smj.Regex, input)
+ return ok && err == nil
+ }
+ if smj.NoEmpty != "" {
+ return input != ""
+ }
+ if smj.Empty != "" {
+ return input == ""
+ }
+ return true
+}
+
+// nolint
+func NewStringMatchJudger(matchConf *config.StringMatch) *StringMatchJudger {
+ return &StringMatchJudger{
+ StringMatch: *matchConf,
+ }
+}
diff --git a/cluster/router/v3router/judger/string_match_judger_test.go b/cluster/router/v3router/judger/string_match_judger_test.go
new file mode 100644
index 0000000..81c25e9
--- /dev/null
+++ b/cluster/router/v3router/judger/string_match_judger_test.go
@@ -0,0 +1,56 @@
+/*
+ * 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 judger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/config"
+)
+
+func TestNewStringMatchJudger(t *testing.T) {
+ assert.True(t, NewStringMatchJudger(&config.StringMatch{
+ Exact: "abc",
+ }).Judge("abc"))
+
+ assert.False(t, NewStringMatchJudger(&config.StringMatch{
+ Exact: "abcd",
+ }).Judge("abc"))
+
+ assert.True(t, NewStringMatchJudger(&config.StringMatch{
+ Prefix: "abc",
+ }).Judge("abcd"))
+
+ assert.False(t, NewStringMatchJudger(&config.StringMatch{
+ Exact: "abcd",
+ }).Judge("abdc"))
+
+ assert.True(t, NewStringMatchJudger(&config.StringMatch{
+ Empty: "true",
+ }).Judge(""))
+
+ assert.False(t, NewStringMatchJudger(&config.StringMatch{
+ NoEmpty: "true",
+ }).Judge(""))
+}
diff --git a/cluster/router/v3router/judger/url_label_match_judge.go b/cluster/router/v3router/judger/url_label_match_judge.go
new file mode 100644
index 0000000..bfb26e4
--- /dev/null
+++ b/cluster/router/v3router/judger/url_label_match_judge.go
@@ -0,0 +1,32 @@
+/*
+ * 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 judger
+
+import (
+ "github.com/apache/dubbo-go/common"
+)
+
+// nolint
+func JudgeUrlLabel(url *common.URL, labels map[string]string) bool {
+ for k, v := range labels {
+ if url.GetParam(k, "") != v {
+ return false
+ }
+ }
+ return true
+}
diff --git a/cluster/router/v3router/k8s_api/k8s.go b/cluster/router/v3router/k8s_api/k8s.go
new file mode 100644
index 0000000..75e8a21
--- /dev/null
+++ b/cluster/router/v3router/k8s_api/k8s.go
@@ -0,0 +1,41 @@
+/*
+ * 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 k8s_api
+
+import (
+ "github.com/apache/dubbo-go/cluster/router/v3router/k8s_crd"
+ "github.com/apache/dubbo-go/config_center"
+)
+
+const (
+ GroupName = "service.dubbo.apache.org"
+ GroupVersion = "v1alpha1"
+ Namespace = "dubbo-workplace"
+)
+
+func SetK8sEventListener(listener config_center.ConfigurationListener) error {
+ vsUniformRouterListenerHandler := newVirtualServiceListenerHandler(listener)
+ drUniformRouterListenerHandler := newDestRuleListenerHandler(listener)
+ k8sCRDClient, err := k8s_crd.NewK8sCRDClient(GroupName, GroupVersion, Namespace,
+ vsUniformRouterListenerHandler, drUniformRouterListenerHandler)
+ if err != nil {
+ return err
+ }
+ k8sCRDClient.WatchResources()
+ return nil
+}
diff --git a/cluster/router/v3router/k8s_api/listener_handler_impl.go b/cluster/router/v3router/k8s_api/listener_handler_impl.go
new file mode 100644
index 0000000..b2f0206
--- /dev/null
+++ b/cluster/router/v3router/k8s_api/listener_handler_impl.go
@@ -0,0 +1,198 @@
+/*
+ * 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 k8s_api
+
+import (
+ metav "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+)
+
+import (
+ "github.com/apache/dubbo-go/cluster/router/v3router/k8s_crd"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/config_center"
+ "github.com/apache/dubbo-go/remoting"
+)
+
+const (
+ VirtualServiceEventKey = "virtualServiceEventKey"
+ DestinationRuleEventKey = "destinationRuleEventKe3y"
+
+ VirtualServiceResource = "virtualservices"
+ DestRuleResource = "destinationrules"
+)
+
+// nolint
+type VirtualServiceListenerHandler struct {
+ listener config_center.ConfigurationListener
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) AddFunc(obj interface{}) {
+ if vsc, ok := obj.(*config.VirtualServiceConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: VirtualServiceEventKey,
+ Value: vsc,
+ ConfigType: remoting.EventTypeAdd,
+ }
+ r.listener.Process(event)
+ }
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) UpdateFunc(oldObj, newObj interface{}) {
+ if vsc, ok := newObj.(*config.VirtualServiceConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: VirtualServiceEventKey,
+ Value: vsc,
+ ConfigType: remoting.EventTypeUpdate,
+ }
+ r.listener.Process(event)
+ }
+
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) DeleteFunc(obj interface{}) {
+ if vsc, ok := obj.(*config.VirtualServiceConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: VirtualServiceEventKey,
+ Value: vsc,
+ ConfigType: remoting.EventTypeDel,
+ }
+ r.listener.Process(event)
+ }
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) Watch(opts metav.ListOptions, restClient *rest.RESTClient, ns string) (watch.Interface, error) {
+ opts.Watch = true
+ return restClient.
+ Get().
+ Namespace(ns).
+ Resource(VirtualServiceResource).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Watch()
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) List(opts metav.ListOptions, restClient *rest.RESTClient, ns string) (runtime.Object, error) {
+ result := config.VirtualServiceConfigList{}
+ err := restClient.
+ Get().
+ Namespace(ns).
+ Resource(VirtualServiceResource).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Do().
+ Into(&result)
+
+ return &result, err
+}
+
+// nolint
+func (r *VirtualServiceListenerHandler) GetObject() runtime.Object {
+ return &config.VirtualServiceConfig{}
+}
+
+// nolint
+func newVirtualServiceListenerHandler(listener config_center.ConfigurationListener) k8s_crd.ListenerHandler {
+ return &VirtualServiceListenerHandler{
+ listener: listener,
+ }
+}
+
+// nolint
+type DestRuleListenerHandler struct {
+ listener config_center.ConfigurationListener
+}
+
+// nolint
+func (r *DestRuleListenerHandler) AddFunc(obj interface{}) {
+ if drc, ok := obj.(*config.DestinationRuleConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: DestinationRuleEventKey,
+ Value: drc,
+ ConfigType: remoting.EventTypeAdd,
+ }
+ r.listener.Process(event)
+ }
+
+}
+
+// nolint
+func (r *DestRuleListenerHandler) UpdateFunc(oldObj, newObj interface{}) {
+ if drc, ok := newObj.(*config.DestinationRuleConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: DestinationRuleEventKey,
+ Value: drc,
+ ConfigType: remoting.EventTypeUpdate,
+ }
+ r.listener.Process(event)
+ }
+}
+
+// nolint
+func (r *DestRuleListenerHandler) DeleteFunc(obj interface{}) {
+ if drc, ok := obj.(*config.DestinationRuleConfig); ok {
+ event := &config_center.ConfigChangeEvent{
+ Key: DestinationRuleEventKey,
+ Value: drc,
+ ConfigType: remoting.EventTypeDel,
+ }
+ r.listener.Process(event)
+ }
+}
+
+// nolint
+func (r *DestRuleListenerHandler) Watch(opts metav.ListOptions, restClient *rest.RESTClient, ns string) (watch.Interface, error) {
+ opts.Watch = true
+ return restClient.
+ Get().
+ Namespace(ns).
+ Resource(DestRuleResource).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Watch()
+}
+
+// nolint
+func (r *DestRuleListenerHandler) List(opts metav.ListOptions, restClient *rest.RESTClient, ns string) (runtime.Object, error) {
+ result := config.DestinationRuleConfigList{}
+ err := restClient.
+ Get().
+ Namespace(ns).
+ Resource(DestRuleResource).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Do().
+ Into(&result)
+
+ return &result, err
+}
+
+// nolint
+func (r *DestRuleListenerHandler) GetObject() runtime.Object {
+ return &config.DestinationRuleConfig{}
+}
+
+func newDestRuleListenerHandler(listener config_center.ConfigurationListener) k8s_crd.ListenerHandler {
+ return &DestRuleListenerHandler{
+ listener: listener,
+ }
+}
diff --git a/cluster/router/v3router/k8s_crd/client.go b/cluster/router/v3router/k8s_crd/client.go
new file mode 100644
index 0000000..5634d68
--- /dev/null
+++ b/cluster/router/v3router/k8s_crd/client.go
@@ -0,0 +1,134 @@
+/*
+ * 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 k8s_crd
+
+import (
+ "sync"
+ "time"
+)
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/cache"
+)
+
+import (
+ "github.com/apache/dubbo-go/common/logger"
+)
+
+type Client struct {
+ rawClient *rest.RESTClient
+ groupVersion schema.GroupVersion
+ namespace string
+ listenerHandlerList []ListenerHandler
+
+ once sync.Once
+}
+
+func (c *Client) addKnownTypes(scheme *runtime.Scheme) error {
+ for _, v := range c.listenerHandlerList {
+ scheme.AddKnownTypes(c.groupVersion,
+ v.GetObject(),
+ )
+ }
+
+ metav1.AddToGroupVersion(scheme, c.groupVersion)
+ return nil
+}
+
+// NewK8sCRDClient create an K8sCRD client, for target CRD objects: @objects
+// with given @groupname, @groupVersion, @namespace
+// list and watchFunction would be called by k8s informer
+func NewK8sCRDClient(groupName, groupVersion, namespace string, handlers ...ListenerHandler) (*Client, error) {
+ var config *rest.Config
+ var err error
+
+ config, err = rest.InClusterConfig()
+ if err != nil {
+ logger.Warn("InClusterConfig failed, can't get uniform router config from k8s")
+ return nil, err
+ }
+
+ newClient := &Client{
+ listenerHandlerList: handlers,
+ namespace: namespace,
+ groupVersion: schema.GroupVersion{Group: groupName, Version: groupVersion},
+ }
+
+ // register object
+ SchemeBuilder := runtime.NewSchemeBuilder(newClient.addKnownTypes)
+
+ // add to scheme
+ if err = SchemeBuilder.AddToScheme(scheme.Scheme); err != nil {
+ logger.Error("AddToScheme failed in k8s CRD process")
+ return nil, err
+ }
+
+ // init crd config
+ crdConfig := *config
+ crdConfig.ContentConfig.GroupVersion = &newClient.groupVersion
+ crdConfig.APIPath = "/apis"
+ crdConfig.NegotiatedSerializer = serializer.NewCodecFactory(scheme.Scheme)
+ crdConfig.UserAgent = rest.DefaultKubernetesUserAgent()
+
+ newRestClient, err := rest.UnversionedRESTClientFor(&crdConfig)
+ if err != nil {
+ logger.Error("InClusterConfig failed, can't get uniform router config from k8s")
+ return nil, err
+ }
+ newClient.rawClient = newRestClient
+ return newClient, nil
+}
+
+// func (c *Client) WatchResources() []cache.Store { can only be called once
+func (c *Client) WatchResources() []cache.Store {
+ stores := make([]cache.Store, 0)
+ c.once.Do(
+ func() {
+ for _, h := range c.listenerHandlerList {
+ projectStore, projectController := cache.NewInformer(
+ &cache.ListWatch{
+ ListFunc: func(lo metav1.ListOptions) (result runtime.Object, err error) {
+ return h.List(lo, c.rawClient, c.namespace)
+ },
+ WatchFunc: func(lo metav1.ListOptions) (watch.Interface, error) {
+ return h.Watch(lo, c.rawClient, c.namespace)
+ },
+ },
+ h.GetObject(),
+ time.Second*30, //todo can be configured
+ cache.ResourceEventHandlerFuncs{
+ AddFunc: h.AddFunc,
+ UpdateFunc: h.UpdateFunc,
+ DeleteFunc: h.DeleteFunc,
+ },
+ )
+
+ go projectController.Run(wait.NeverStop)
+ stores = append(stores, projectStore)
+ }
+ })
+ return stores
+}
diff --git a/cluster/router/v3router/k8s_crd/deploy/unifom_router_crd.yml b/cluster/router/v3router/k8s_crd/deploy/unifom_router_crd.yml
new file mode 100644
index 0000000..9acc7d7
--- /dev/null
+++ b/cluster/router/v3router/k8s_crd/deploy/unifom_router_crd.yml
@@ -0,0 +1,43 @@
+apiVersion: "apiextensions.k8s.io/v1"
+kind: "CustomResourceDefinition"
+metadata:
+ name: "virtualservices.service.dubbo.apache.org"
+spec:
+ group: "service.dubbo.apache.org"
+ versions:
+ - name: "v1alpha1"
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ type: object
+ properties:
+ spec:
+ type: object
+ scope: "Namespaced"
+ names:
+ plural: "virtualservices"
+ singular: "virtualservice"
+ kind: "VirtualService"
+---
+apiVersion: "apiextensions.k8s.io/v1"
+kind: "CustomResourceDefinition"
+metadata:
+ name: "destinationrules.service.dubbo.apache.org"
+spec:
+ group: "service.dubbo.apache.org"
+ versions:
+ - name: "v1alpha1"
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ type: object
+ properties:
+ spec:
+ type: object
+ scope: "Namespaced"
+ names:
+ plural: "destinationrules"
+ singular: "destinationrule"
+ kind: "DestinationRule"
\ No newline at end of file
diff --git a/cluster/router/v3router/k8s_crd/listener_handler.go b/cluster/router/v3router/k8s_crd/listener_handler.go
new file mode 100644
index 0000000..2a52291
--- /dev/null
+++ b/cluster/router/v3router/k8s_crd/listener_handler.go
@@ -0,0 +1,35 @@
+/*
+ * 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 k8s_crd
+
+import (
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/rest"
+)
+
+// nolint
+type ListenerHandler interface {
+ AddFunc(obj interface{})
+ UpdateFunc(oldObj interface{}, newObj interface{})
+ DeleteFunc(obj interface{})
+ Watch(opts v1.ListOptions, restClient *rest.RESTClient, ns string) (watch.Interface, error)
+ List(opts v1.ListOptions, restClient *rest.RESTClient, ns string) (runtime.Object, error)
+ GetObject() runtime.Object
+}
diff --git a/cluster/router/v3router/router_chain.go b/cluster/router/v3router/router_chain.go
new file mode 100644
index 0000000..4b03c1b
--- /dev/null
+++ b/cluster/router/v3router/router_chain.go
@@ -0,0 +1,246 @@
+/*
+ * 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 v3router
+
+import (
+ "encoding/json"
+ "io"
+ "strings"
+)
+
+import (
+ "gopkg.in/yaml.v2"
+)
+
+import (
+ "github.com/apache/dubbo-go/cluster/router"
+ "github.com/apache/dubbo-go/cluster/router/v3router/k8s_api"
+ "github.com/apache/dubbo-go/common"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/config_center"
+ "github.com/apache/dubbo-go/protocol"
+ "github.com/apache/dubbo-go/remoting"
+)
+
+// RouterChain contains all uniform router logic
+// it has UniformRouter list,
+type RouterChain struct {
+ routers []*UniformRouter
+ virtualServiceConfigBytes []byte
+ destinationRuleConfigBytes []byte
+ notify chan struct{}
+}
+
+// NewUniformRouterChain return
+func NewUniformRouterChain(virtualServiceConfig, destinationRuleConfig []byte, notify chan struct{}) (router.PriorityRouter, error) {
+ fromFileConfig := true
+ uniformRouters, err := parseFromConfigToRouters(virtualServiceConfig, destinationRuleConfig, notify)
+ if err != nil {
+ fromFileConfig = false
+ logger.Warnf("parse router config form local file failed, error = %+v", err)
+ }
+ r := &RouterChain{
+ virtualServiceConfigBytes: virtualServiceConfig,
+ destinationRuleConfigBytes: destinationRuleConfig,
+ routers: uniformRouters,
+ notify: notify,
+ }
+ if err := k8s_api.SetK8sEventListener(r); err != nil {
+ logger.Warnf("try listen K8s router config failed, error = %+v", err)
+ if !fromFileConfig {
+ panic("No config file from both local file and k8s")
+ }
+ }
+ return r, nil
+}
+
+// Route route invokers using RouterChain's routers one by one
+func (r *RouterChain) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+ for _, v := range r.routers {
+ invokers = v.Route(invokers, url, invocation)
+ }
+ return invokers
+}
+
+func (r *RouterChain) Process(event *config_center.ConfigChangeEvent) {
+ logger.Debugf("on processed event = %+v\n", *event)
+ if event.ConfigType == remoting.EventTypeAdd || event.ConfigType == remoting.EventTypeUpdate {
+ switch event.Key {
+ case k8s_api.VirtualServiceEventKey:
+ logger.Debug("virtul service event")
+ newVSValue, ok := event.Value.(*config.VirtualServiceConfig)
+ if !ok {
+ logger.Error("event.Value assertion error")
+ return
+ }
+
+ newVSJsonValue, ok := newVSValue.ObjectMeta.Annotations["kubectl.kubernetes.io/last-applied-configuration"]
+ if !ok {
+ logger.Error("newVSValue.ObjectMeta.Annotations has no key named kubectl.kubernetes.io/last-applied-configuration")
+ return
+ }
+ logger.Debugf("json file = %v\n", newVSJsonValue)
+ newVirtualServiceConfig := &config.VirtualServiceConfig{}
+ if err := json.Unmarshal([]byte(newVSJsonValue), newVirtualServiceConfig); err != nil {
+ logger.Error("on process json data unmarshal error = ", err)
+ return
+ }
+ newVirtualServiceConfig.YamlAPIVersion = newVirtualServiceConfig.APIVersion
+ newVirtualServiceConfig.YamlKind = newVirtualServiceConfig.Kind
+ newVirtualServiceConfig.MetaData.Name = newVirtualServiceConfig.ObjectMeta.Name
+ logger.Debugf("get event after asseration = %+v\n", newVirtualServiceConfig)
+ data, err := yaml.Marshal(newVirtualServiceConfig)
+ if err != nil {
+ logger.Error("Process change of virtual service: event.Value marshal error:", err)
+ return
+ }
+ r.routers, err = parseFromConfigToRouters(data, r.destinationRuleConfigBytes, r.notify)
+ if err != nil {
+ logger.Error("Process change of virtual service: parseFromConfigToRouters:", err)
+ return
+ }
+ case k8s_api.DestinationRuleEventKey:
+ logger.Debug("handling dest rule event")
+ newDRValue, ok := event.Value.(*config.DestinationRuleConfig)
+ if !ok {
+ logger.Error("event.Value assertion error")
+ return
+ }
+
+ newDRJsonValue, ok := newDRValue.ObjectMeta.Annotations["kubectl.kubernetes.io/last-applied-configuration"]
+ if !ok {
+ logger.Error("newVSValue.ObjectMeta.Annotations has no key named kubectl.kubernetes.io/last-applied-configuration")
+ return
+ }
+ newDestRuleConfig := &config.DestinationRuleConfig{}
+ if err := json.Unmarshal([]byte(newDRJsonValue), newDestRuleConfig); err != nil {
+ logger.Error("on process json data unmarshal error = ", err)
+ return
+ }
+ newDestRuleConfig.YamlAPIVersion = newDestRuleConfig.APIVersion
+ newDestRuleConfig.YamlKind = newDestRuleConfig.Kind
+ newDestRuleConfig.MetaData.Name = newDestRuleConfig.ObjectMeta.Name
+ logger.Debugf("get event after asseration = %+v\n", newDestRuleConfig)
+ data, err := yaml.Marshal(newDestRuleConfig)
+ if err != nil {
+ logger.Error("Process change of dest rule: event.Value marshal error:", err)
+ return
+ }
+ r.routers, err = parseFromConfigToRouters(r.virtualServiceConfigBytes, data, r.notify)
+ if err != nil {
+ logger.Error("Process change of dest rule: parseFromConfigToRouters:", err)
+ return
+ }
+ default:
+ logger.Error("unknow unsupported event key:", event.Key)
+ }
+ }
+
+ // todo delete router
+ //if event.ConfigType == remoting.EventTypeDel {
+ //
+ //}
+}
+
+// Name get name of ConnCheckerRouter
+func (r *RouterChain) Name() string {
+ return name
+}
+
+// Priority get Router priority level
+func (r *RouterChain) Priority() int64 {
+ return 0
+}
+
+// URL Return URL in router
+func (r *RouterChain) URL() *common.URL {
+ return nil
+}
+
+// parseFromConfigToRouters parse virtualService and destinationRule yaml file bytes to target router list
+func parseFromConfigToRouters(virtualServiceConfig, destinationRuleConfig []byte, notify chan struct{}) ([]*UniformRouter, error) {
+ var virtualServiceConfigList []*config.VirtualServiceConfig
+ destRuleConfigsMap := make(map[string]map[string]map[string]string)
+
+ vsDecoder := yaml.NewDecoder(strings.NewReader(string(virtualServiceConfig)))
+ drDecoder := yaml.NewDecoder(strings.NewReader(string(destinationRuleConfig)))
+ for {
+ virtualServiceCfg := &config.VirtualServiceConfig{}
+
+ err := vsDecoder.Decode(virtualServiceCfg)
+ if err == io.EOF {
+ break
+ }
+
+ if err != nil {
+ logger.Error("parseFromConfigTo virtual service err = ", err)
+ return nil, err
+ }
+ virtualServiceConfigList = append(virtualServiceConfigList, virtualServiceCfg)
+ }
+
+ for {
+ destRuleCfg := &config.DestinationRuleConfig{}
+ err := drDecoder.Decode(destRuleCfg)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ logger.Error("parseFromConfigTo destination rule err = ", err)
+ return nil, err
+ }
+ destRuleCfgMap := make(map[string]map[string]string)
+ for _, v := range destRuleCfg.Spec.SubSets {
+ destRuleCfgMap[v.Name] = v.Labels
+ }
+ destRuleConfigsMap[destRuleCfg.Spec.Host] = destRuleCfgMap
+ }
+
+ routers := make([]*UniformRouter, 0)
+
+ for _, v := range virtualServiceConfigList {
+ tempSerivceNeedsDescMap := make(map[string]map[string]string)
+ for _, host := range v.Spec.Hosts {
+ targetDestMap := destRuleConfigsMap[host]
+
+ // copy to new Map
+ mapCombine(tempSerivceNeedsDescMap, targetDestMap)
+ }
+ // change single config to one rule
+ newRule, err := newDubboRouterRule(v.Spec.Dubbo, tempSerivceNeedsDescMap)
+ if err != nil {
+ logger.Error("Parse config to uniform rule err = ", err)
+ return nil, err
+ }
+ rtr, err := NewUniformRouter(newRule, notify)
+ if err != nil {
+ logger.Error("new uniform router err = ", err)
+ return nil, err
+ }
+ routers = append(routers, rtr)
+ }
+ logger.Debug("parsed successed! with router size = ", len(routers))
+ return routers, nil
+}
+
+func mapCombine(dist map[string]map[string]string, from map[string]map[string]string) {
+ for k, v := range from {
+ dist[k] = v
+ }
+}
diff --git a/cluster/router/v3router/router_chain_test.go b/cluster/router/v3router/router_chain_test.go
new file mode 100644
index 0000000..4e05de9
--- /dev/null
+++ b/cluster/router/v3router/router_chain_test.go
@@ -0,0 +1,208 @@
+/*
+ * 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 v3router
+
+import (
+ "fmt"
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "github.com/apache/dubbo-go/common"
+ "github.com/apache/dubbo-go/common/yaml"
+ "github.com/apache/dubbo-go/protocol"
+ "github.com/apache/dubbo-go/protocol/invocation"
+)
+
+const (
+ mockVSConfigPath = "./test_file/virtual_service.yml"
+ mockDRConfigPath = "./test_file/dest_rule.yml"
+)
+
+func TestNewUniformRouterChain(t *testing.T) {
+ vsBytes, _ := yaml.LoadYMLConfig(mockVSConfigPath)
+ drBytes, _ := yaml.LoadYMLConfig(mockDRConfigPath)
+ rc, err := NewUniformRouterChain(vsBytes, drBytes, make(chan struct{}))
+ assert.Nil(t, err)
+ assert.NotNil(t, rc)
+}
+
+type ruleTestItemStruct struct {
+ name string
+ matchMethodNameExact string
+ RouterDestHost string
+ RouterDestSubset string
+ RouterFallBackDestHost string
+ RouterFallBackDestSubset string
+ RouterFallBackFallBackDestHost string
+ RouterFallBackFallBackDestSubset string
+ fallbackLevel int
+ RouterSize int
+}
+
+func TestParseConfigFromFile(t *testing.T) {
+ vsBytes, _ := yaml.LoadYMLConfig(mockVSConfigPath)
+ drBytes, _ := yaml.LoadYMLConfig(mockDRConfigPath)
+ routers, err := parseFromConfigToRouters(vsBytes, drBytes, make(chan struct{}, 1))
+ fmt.Println(routers, err)
+ assert.Equal(t, len(routers), 1)
+ assert.NotNil(t, routers[0].dubboRouter)
+ assert.Equal(t, len(routers[0].dubboRouter.uniformRules), 2)
+ for i, v := range routers[0].dubboRouter.uniformRules {
+ if i == 0 {
+ assert.Equal(t, len(v.services), 2)
+ assert.Equal(t, "com.taobao.hsf.demoService:1.0.0", v.services[0].Exact)
+ assert.Equal(t, "", v.services[0].Regex)
+ assert.Equal(t, "", v.services[0].NoEmpty)
+ assert.Equal(t, "", v.services[0].Empty)
+ assert.Equal(t, "", v.services[0].Prefix)
+
+ assert.Equal(t, "com.taobao.hsf.demoService:2.0.0", v.services[1].Exact)
+ assert.Equal(t, "", v.services[1].Regex)
+ assert.Equal(t, "", v.services[1].NoEmpty)
+ assert.Equal(t, "", v.services[1].Empty)
+ assert.Equal(t, "", v.services[1].Prefix)
+
+ assert.Equal(t, len(v.virtualServiceRules), 4)
+
+ ruleTestItemStructList := []ruleTestItemStruct{
+ {
+ name: "sayHello-String-method-route",
+ matchMethodNameExact: "sayHello",
+ RouterDestHost: "demo",
+ RouterDestSubset: "v1",
+ RouterFallBackDestHost: "demo",
+ RouterFallBackDestSubset: "v2",
+ RouterFallBackFallBackDestHost: "demo",
+ RouterFallBackFallBackDestSubset: "v3",
+ RouterSize: 1,
+ fallbackLevel: 3,
+ },
+ {
+ name: "sayHello-method-route",
+ matchMethodNameExact: "s-method",
+ RouterDestHost: "demo",
+ RouterDestSubset: "v2",
+ RouterFallBackDestHost: "demo",
+ RouterFallBackDestSubset: "v3",
+ RouterSize: 1,
+ fallbackLevel: 2,
+ },
+ {
+ name: "some-method-route",
+ matchMethodNameExact: "some-method",
+ RouterDestHost: "demo",
+ RouterDestSubset: "v4",
+ RouterSize: 1,
+ fallbackLevel: 1,
+ },
+ {
+ name: "final",
+ matchMethodNameExact: "GetUser",
+ RouterDestHost: "demo",
+ RouterDestSubset: "v1",
+ RouterFallBackDestHost: "demo",
+ RouterFallBackDestSubset: "v2",
+ RouterFallBackFallBackDestHost: "demo",
+ RouterFallBackFallBackDestSubset: "v3",
+ RouterSize: 2,
+ fallbackLevel: 3,
+ },
+ }
+ for i, vsRule := range v.virtualServiceRules {
+ assert.NotNil(t, v.virtualServiceRules[i].routerItem)
+ assert.Equal(t, ruleTestItemStructList[i].name, vsRule.routerItem.Name)
+ assert.Equal(t, 1, len(vsRule.routerItem.Match))
+ assert.NotNil(t, vsRule.routerItem.Match[0].Method)
+ assert.Equal(t, ruleTestItemStructList[i].matchMethodNameExact, vsRule.routerItem.Match[0].Method.NameMatch.Exact)
+ assert.Equal(t, ruleTestItemStructList[i].RouterSize, len(vsRule.routerItem.Router))
+ assert.NotNil(t, vsRule.routerItem.Router[0].Destination)
+ assert.Equal(t, ruleTestItemStructList[i].RouterDestHost, vsRule.routerItem.Router[0].Destination.Host)
+ assert.Equal(t, ruleTestItemStructList[i].RouterDestSubset, vsRule.routerItem.Router[0].Destination.Subset)
+ if vsRule.routerItem.Router[0].Destination.Fallback == nil {
+ assert.Equal(t, 1, ruleTestItemStructList[i].fallbackLevel)
+ continue
+ }
+ newRule := vsRule.routerItem.Router[0].Destination.Fallback
+ assert.NotNil(t, newRule.Destination)
+ assert.Equal(t, ruleTestItemStructList[i].RouterFallBackDestHost, newRule.Destination.Host)
+ assert.Equal(t, ruleTestItemStructList[i].RouterFallBackDestSubset, newRule.Destination.Subset)
+ if newRule.Destination.Fallback == nil {
+ assert.Equal(t, 2, ruleTestItemStructList[i].fallbackLevel)
+ continue
+ }
+
+ newRule = newRule.Destination.Fallback
+ assert.NotNil(t, newRule.Destination)
+ assert.Equal(t, ruleTestItemStructList[i].RouterFallBackFallBackDestHost, newRule.Destination.Host)
+ assert.Equal(t, ruleTestItemStructList[i].RouterFallBackFallBackDestSubset, newRule.Destination.Subset)
+ if newRule.Destination.Fallback == nil {
+ assert.Equal(t, 3, ruleTestItemStructList[i].fallbackLevel)
+ }
+ }
+
+ destMap := v.DestinationLabelListMap
+ v1Val, ok := destMap["v1"]
+ assert.True(t, ok)
+ v1SigmaVal, ok := v1Val["sigma.ali/mg"]
+ assert.True(t, ok)
+ assert.Equal(t, "v1-host", v1SigmaVal)
+ v1Generic, ok := v1Val["generic"]
+ assert.True(t, ok)
+ assert.Equal(t, "false", v1Generic)
+
+ v2Val, ok := destMap["v2"]
+ assert.True(t, ok)
+ v2Generic, ok := v2Val["generic"]
+ assert.True(t, ok)
+ assert.Equal(t, "false", v2Generic)
+
+ v3Val, ok := destMap["v3"]
+ assert.True(t, ok)
+ v3SigmaVal, ok := v3Val["sigma.ali/mg"]
+ assert.True(t, ok)
+ assert.Equal(t, "v3-host", v3SigmaVal)
+
+ }
+ }
+}
+
+func TestRouterChain_Route(t *testing.T) {
+ vsBytes, _ := yaml.LoadYMLConfig(mockVSConfigPath)
+ drBytes, _ := yaml.LoadYMLConfig(mockDRConfigPath)
+ rc, err := NewUniformRouterChain(vsBytes, drBytes, make(chan struct{}))
+ assert.Nil(t, err)
+ assert.NotNil(t, rc)
+ newGoodURL, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+ newBadURL1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+ newBadURL2, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
+ goodIvk := protocol.NewBaseInvoker(newGoodURL)
+ b1 := protocol.NewBaseInvoker(newBadURL1)
+ b2 := protocol.NewBaseInvoker(newBadURL2)
+ invokerList := make([]protocol.Invoker, 3)
+ invokerList = append(invokerList, goodIvk)
+ invokerList = append(invokerList, b1)
+ invokerList = append(invokerList, b2)
+ result := rc.Route(invokerList, newGoodURL, invocation.NewRPCInvocation("GetUser", nil, nil))
+ assert.Equal(t, 0, len(result))
+ //todo test find target invoker
+}
diff --git a/cluster/router/v3router/test_file/dest_rule.yml b/cluster/router/v3router/test_file/dest_rule.yml
new file mode 100644
index 0000000..89bd88f
--- /dev/null
+++ b/cluster/router/v3router/test_file/dest_rule.yml
@@ -0,0 +1,17 @@
+apiVersion: service.dubbo.apache.org/v1alpha1
+kind: DestinationRule
+metadata:
+ name: demo-route
+spec:
+ host: demo
+ subsets:
+ - name: v1
+ labels:
+ sigma.ali/mg: v1-host
+ generic: false
+ - name: v2
+ labels:
+ generic: false
+ - name: v3
+ labels:
+ sigma.ali/mg: v3-host
\ No newline at end of file
diff --git a/cluster/router/v3router/test_file/virtual_service.yml b/cluster/router/v3router/test_file/virtual_service.yml
new file mode 100644
index 0000000..1c6b751
--- /dev/null
+++ b/cluster/router/v3router/test_file/virtual_service.yml
@@ -0,0 +1,158 @@
+apiVersion: service.dubbo.apache.org/v1alpha1
+kind: VirtualService
+metadata:
+ name: demo-route
+spec:
+ hosts:
+ - demo # app name
+ dubbo:
+ - services:
+ - exact: com.taobao.hsf.demoService:1.0.0
+ - exact: com.taobao.hsf.demoService:2.0.0
+ routedetail:
+ - name: sayHello-String-method-route
+ match:
+ - method:
+ name_match:
+ exact: "sayHello"
+ # argp:
+ # - string
+ route:
+ - destination:
+ host: demo
+ subset: v1
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+
+ - name: sayHello-method-route
+ match:
+ - method:
+ name_match:
+ exact: "s-method"
+ route:
+ - destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+ - name: some-method-route
+ match:
+ - method:
+ name_match:
+ exact: "some-method"
+ route:
+ - destination:
+ host: demo
+ subset: v4
+ - name: final
+ match:
+ - method:
+ name_match:
+ exact: "GetUser"
+
+ route:
+ - destination:
+ host: demo
+ subset: v1
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+ - destination:
+ host: demo
+ subset: v3
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v1
+ - services:
+ - exact: com.taobao.hsf.demoService:1.0.0
+ - exact: org.apache.dubbo.UserProvider
+ routedetail:
+ - name: sayHello-String-method-route
+ match:
+ - method:
+ name_match:
+ exact: "sayHello"
+ # argp:
+ # - string
+ route:
+ - destination:
+ host: demo
+ subset: v1
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+
+ - name: sayHello-method-route
+ match:
+ - method:
+ name_match:
+ exact: "s-method"
+ route:
+ - destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+ - name: some-method-route
+ match:
+ - method:
+ name_match:
+ exact: "some-method"
+ route:
+ - destination:
+ host: demo
+ subset: v4
+ - name: final
+ match:
+ - method:
+ name_match:
+ exact: "GetUser"
+
+ route:
+ - destination:
+ host: demo
+ subset: v1
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+ - destination:
+ host: demo
+ subset: v3
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v1
\ No newline at end of file
diff --git a/cluster/router/v3router/uniform_route.go b/cluster/router/v3router/uniform_route.go
new file mode 100644
index 0000000..c11c296
--- /dev/null
+++ b/cluster/router/v3router/uniform_route.go
@@ -0,0 +1,67 @@
+/*
+ * 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 v3router
+
+import (
+ "github.com/apache/dubbo-go/common"
+ "github.com/apache/dubbo-go/config_center"
+ "github.com/apache/dubbo-go/protocol"
+)
+
+const (
+ name = "uniform-router"
+)
+
+// UniformRouter have
+type UniformRouter struct {
+ dubboRouter *DubboRouterRule
+ notify chan struct{}
+}
+
+// NewUniformRouter construct an NewConnCheckRouter via url
+func NewUniformRouter(dubboRouter *DubboRouterRule, notify chan struct{}) (*UniformRouter, error) {
+ r := &UniformRouter{
+ dubboRouter: dubboRouter,
+ notify: notify,
+ }
+ return r, nil
+}
+
+// Route gets a list of routed invoker
+func (r *UniformRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+ return r.dubboRouter.route(invokers, url, invocation)
+}
+
+// Process there is no process needs for uniform Router, as it upper struct RouterChain has done it
+func (r *UniformRouter) Process(event *config_center.ConfigChangeEvent) {
+}
+
+// Name get name of ConnCheckerRouter
+func (r *UniformRouter) Name() string {
+ return name
+}
+
+// Priority get Router priority level
+func (r *UniformRouter) Priority() int64 {
+ return 0
+}
+
+// URL Return URL in router
+func (r *UniformRouter) URL() *common.URL {
+ return nil
+}
diff --git a/cluster/router/v3router/uniform_rule.go b/cluster/router/v3router/uniform_rule.go
new file mode 100644
index 0000000..f7e8148
--- /dev/null
+++ b/cluster/router/v3router/uniform_rule.go
@@ -0,0 +1,257 @@
+/*
+ * 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 v3router
+
+import (
+ "math/rand"
+ "time"
+)
+
+import (
+ perrors "github.com/pkg/errors"
+)
+
+import (
+ "github.com/apache/dubbo-go/cluster/router/v3router/judger"
+ "github.com/apache/dubbo-go/common"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/protocol"
+)
+
+// VirtualServiceRule is item of virtual service, it aims at judge if invocation context match it's condition, and
+// if match, get result destination key, which should be defined in DestinationRule yaml file
+type VirtualServiceRule struct {
+ // routerItem store match router list and destination list of this router
+ routerItem *config.DubboServiceRouterItem
+
+ // uniformRule is the upper struct ptr
+ uniformRule *UniformRule
+}
+
+// match read from vsr's Match config
+// it judges if this invocation matches the router rule request defined in config one by one
+func (vsr *VirtualServiceRule) match(url *common.URL, invocation protocol.Invocation) bool {
+ for _, v := range vsr.routerItem.Match {
+ // method match judge
+ if v.Method != nil {
+ methodMatchJudger := judger.NewMethodMatchJudger(v.Method)
+ if !methodMatchJudger.Judge(invocation) {
+ return false
+ }
+ }
+
+ // source label match judge
+ if !judger.JudgeUrlLabel(url, v.SourceLabels) {
+ return false
+ }
+
+ // atta match judge
+ if v.Attachment != nil {
+ attachmentMatchJudger := judger.NewAttachmentMatchJudger(v.Attachment)
+ if attachmentMatchJudger.Judge(invocation) {
+ return false
+ }
+ }
+ // threshold match judge
+ // todo
+
+ // reserve match judge
+ // todo
+ }
+ return true
+}
+
+// tryGetSubsetFromRouterOfOneDestination is a recursion function
+// try from destination 's header to final fallback destination, when success, it return result destination, else return error
+func (vsr *VirtualServiceRule) tryGetSubsetFromRouterOfOneDestination(desc *config.DubboDestination, invokers []protocol.Invoker) ([]protocol.Invoker, int, error) {
+ subSet := desc.Destination.Subset
+ labels, ok := vsr.uniformRule.DestinationLabelListMap[subSet]
+ resultInvokers := make([]protocol.Invoker, 0)
+ if ok {
+ for _, v := range invokers {
+ if judger.JudgeUrlLabel(v.GetURL(), labels) {
+ resultInvokers = append(resultInvokers, v)
+ }
+ }
+ if len(resultInvokers) != 0 {
+ return resultInvokers, desc.Destination.Weight, nil
+ }
+ }
+
+ if desc.Destination.Fallback != nil {
+ return vsr.tryGetSubsetFromRouterOfOneDestination(desc.Destination.Fallback, invokers)
+ }
+ return nil, 0, perrors.New("No invoker matches and no fallback destination to choose!")
+}
+
+//weightInvokersPair stores weight and invoker list.
+type weightInvokersPair struct {
+ weight int
+ invokerList []protocol.Invoker
+}
+
+type weightInvokerPairResults struct {
+ pairs []weightInvokersPair
+}
+
+func (w *weightInvokerPairResults) getTargetInvokers() []protocol.Invoker {
+ if len(w.pairs) == 0 {
+ return []protocol.Invoker{}
+ }
+
+ if len(w.pairs) == 1 {
+ return w.pairs[0].invokerList
+ }
+ rand.Seed(time.Now().UnixNano())
+ target := rand.Intn(100)
+ // noweight means all weigh is zero, random choose one invoker list
+ noWeight := true
+ // check if empty
+ for _, v := range w.pairs {
+ if v.weight != 0 {
+ noWeight = false // user defined weight
+ break
+ }
+ }
+ if noWeight {
+ // random choose one list
+ weitUnit := 100/len(w.pairs) + 1
+ return w.pairs[target/weitUnit].invokerList
+ } else {
+ total := 0
+ for _, v := range w.pairs {
+ total += v.weight
+ if total > target {
+ return v.invokerList
+ }
+ }
+ }
+ // invalid weight set: total is smaller than 100, choose first
+ return w.pairs[0].invokerList
+}
+
+func (vsr *VirtualServiceRule) getRuleTargetInvokers(invokers []protocol.Invoker) ([]protocol.Invoker, error) {
+ // weightInvokerPairResult is the collection routerDesc of all destination fields,
+ weightInvokerPairResult := weightInvokerPairResults{}
+ for _, v := range vsr.routerItem.Router {
+ // v is one destination 's header e.g.
+ /*
+ route:
+ - destination: # v is here
+ host: demo
+ subset: v1
+ fallback:
+ destination:
+ host: demo
+ subset: v2
+ fallback:
+ destination:
+ host: demo
+ subset: v3
+ - destination:
+ host: demo
+ subset: v4
+ fallback:
+ destination:
+ host: demo
+ subset: v5
+ fallback:
+ destination:
+ host: demo
+ subset: v6
+ */
+ invokerListOfOneDest, weight, err := vsr.tryGetSubsetFromRouterOfOneDestination(v, invokers)
+ if err != nil {
+ return nil, err
+ }
+ // combination of all destination field e.g.
+ /*
+ - destination:
+ host: demo
+ subset: na61
+ - destination:
+ host: demo
+ subset: na610
+ */
+ weightInvokerPairResult.pairs = append(weightInvokerPairResult.pairs, weightInvokersPair{
+ weight: weight,
+ invokerList: invokerListOfOneDest,
+ })
+ }
+
+ return weightInvokerPairResult.getTargetInvokers(), nil
+}
+
+// UniformRule
+type UniformRule struct {
+ services []*config.StringMatch
+ virtualServiceRules []VirtualServiceRule
+ DestinationLabelListMap map[string]map[string]string
+}
+
+// NewDefaultConnChecker constructs a new DefaultConnChecker based on the url
+func newUniformRule(dubboRoute *config.DubboRoute, destinationMap map[string]map[string]string) (*UniformRule, error) {
+ matchItems := dubboRoute.RouterDetail
+ virtualServiceRules := make([]VirtualServiceRule, 0)
+ newUniformRule := &UniformRule{
+ DestinationLabelListMap: destinationMap,
+ services: dubboRoute.Services,
+ }
+ for _, v := range matchItems {
+ virtualServiceRules = append(virtualServiceRules, VirtualServiceRule{
+ routerItem: v,
+ uniformRule: newUniformRule,
+ })
+ }
+ newUniformRule.virtualServiceRules = virtualServiceRules
+ return newUniformRule, nil
+}
+
+func (u *UniformRule) route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+ // service rule + destination -> filter
+ resultInvokers := make([]protocol.Invoker, 0)
+ var err error
+ matchService := false
+ for _, v := range u.services {
+ // check if match service field
+ if judger.NewStringMatchJudger(v).Judge(url.ServiceKey()) {
+ matchService = true
+ break
+ }
+ }
+ if !matchService {
+ // if not match, jump this rule
+ return resultInvokers
+ }
+ // match service field, route Details level(service level) match
+ // then, check all sub rule, if match, get destination rule target invokers, else do fail back logic
+ for _, rule := range u.virtualServiceRules {
+ if rule.match(url, invocation) {
+ // match this rule, do get target logic
+ resultInvokers, err = rule.getRuleTargetInvokers(invokers)
+ if err != nil {
+ logger.Error("getRuleTargetInvokers from rule err = ", err)
+ return nil
+ }
+ return resultInvokers
+ }
+ }
+ logger.Errorf("no match rule for invokers %+v", invokers)
+ return resultInvokers
+}
diff --git a/config/uniform_router_config.go b/config/uniform_router_config.go
new file mode 100644
index 0000000..e18c07c
--- /dev/null
+++ b/config/uniform_router_config.go
@@ -0,0 +1,231 @@
+/*
+ * 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 config
+
+import (
+ "github.com/ghodss/yaml"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// nolint
+type MetaDataStruct struct {
+ Name string `yaml:"name"`
+}
+
+// VirtualService Config Definition
+type VirtualServiceConfig struct {
+ YamlAPIVersion string `yaml:"apiVersion"`
+ YamlKind string `yaml:"kind"`
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+ MetaData MetaDataStruct `yaml:"metadata"`
+ Spec UniformRouterConfigSpec `yaml:"spec" json:"spec"`
+}
+
+// nolint
+type UniformRouterConfigSpec struct {
+ Hosts []string `yaml:"hosts" json:"hosts"`
+ Dubbo []*DubboRoute `yaml:"dubbo" json:"dubbo"`
+}
+
+// nolint
+type DubboRoute struct {
+ Services []*StringMatch `yaml:"services" json:"service"`
+ RouterDetail []*DubboServiceRouterItem `yaml:"routedetail" json:"routedetail"`
+}
+
+// nolint
+type DubboServiceRouterItem struct {
+ Name string `yaml:"name" json:"name"`
+ Match []*DubboMatchRequest `yaml:"match" json:"match"`
+ Router []*DubboDestination `yaml:"route" json:"route"`
+ // todo mirror/retries/timeout
+}
+
+// nolint
+type DubboMatchRequest struct {
+ Name string `yaml:"name" json:"name"`
+ Method *DubboMethodMatch `yaml:"method" json:"method"`
+ SourceLabels map[string]string `yaml:"sourceLabels" json:"sourceLabels"`
+ Attachment *DubboAttachmentMatch `yaml:"attachments" json:"attachments"`
+ Header map[string]*StringMatch `yaml:"headers" json:"headers"`
+ Threshold *DoubleMatch `yaml:"threshold" json:"threshold"`
+}
+
+// nolint
+type DoubleMatch struct {
+ Exact float64 `yaml:"exact" json:"exact"`
+ Range *DoubleRangeMatch `yaml:"range" json:"range"`
+ Mode float64 `yaml:"mode" json:"mode"`
+}
+
+// nolint
+type DoubleRangeMatch struct {
+ Start float64 `yaml:"start" json:"start"`
+ End float64 `yaml:"end" json:"end"`
+}
+
+// nolint
+type DubboAttachmentMatch struct {
+ EagleeyeContext map[string]*StringMatch `yaml:"eagleeyecontext" json:"eagleeyecontext"`
+ DubboContext map[string]*StringMatch `yaml:"dubbocontext" json:"dubbocontext"`
+}
+
+// nolint
+type DubboMethodMatch struct {
+ NameMatch *StringMatch `yaml:"name_match" json:"name_match"`
+ Argc int `yaml:"argc" json:"argc"`
+ Args []*DubboMethodArg `yaml:"args" json:"args"`
+ Argp []*StringMatch `yaml:"argp" json:"argp"`
+ Headers map[string]*StringMatch `yaml:"headers" json:"headers"`
+}
+
+// nolint
+type DubboMethodArg struct {
+ Index uint32 `yaml:"index" json:"index"`
+ Type string `yaml:"type" json:"type"`
+ StrValue *ListStringMatch `yaml:"str_value" json:"str_value"`
+ NumValue *ListDoubleMatch `yaml:"num_value" json:"num_value"`
+ BoolValue *BoolMatch `yaml:"bool_value" json:"bool_value"`
+ //todo reserve field
+}
+
+// nolint
+type ListStringMatch struct {
+ Oneof []*StringMatch `yaml:"oneof" json:"oneof"`
+}
+
+// nolint
+type ListDoubleMatch struct {
+ Oneof []*DoubleMatch `yaml:"oneof" json:"oneof"`
+}
+
+// nolint
+type BoolMatch struct {
+ Exact bool `yaml:"exact" json:"exact"`
+}
+
+// nolint
+type StringMatch struct {
+ Exact string `yaml:"exact" json:"exact"`
+ Prefix string `yaml:"prefix" json:"prefix"`
+ Regex string `yaml:"regex" json:"regex"`
+ NoEmpty string `yaml:"noempty" json:"noempty"`
+ Empty string `yaml:"empty" json:"empty"`
+}
+
+// nolint
+type DubboDestination struct {
+ Destination RouterDest `yaml:"destination" json:"destination"`
+ //Subset string `yaml:"subset"`
+}
+
+// nolint
+type RouterDest struct {
+ Host string `yaml:"host" json:"host"`
+ Subset string `yaml:"subset" json:"subset"`
+ Weight int `yaml:"weight" json:"weight"`
+ Fallback *DubboDestination `yaml:"fallback" json:"fallback"`
+ // todo port
+}
+
+// DestinationRule Definition
+type DestinationRuleConfig struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+ YamlAPIVersion string `yaml:"apiVersion" `
+ YamlKind string `yaml:"kind" `
+ MetaData MetaDataStruct `yaml:"metadata"`
+ Spec DestinationRuleSpec `yaml:"spec" json:"spec"`
+}
+
+// nolint
+func (drc *DestinationRuleConfig) DeepCopyObject() runtime.Object {
+ data, _ := yaml.Marshal(drc)
+ out := &DestinationRuleConfig{}
+ yaml.Unmarshal(data, out)
+ return out
+}
+
+// nolint
+type DestinationRuleSpec struct {
+ Host string `yaml:"host" json:"host"`
+ SubSets []DestinationRuleSubSet `yaml:"subsets" json:"subsets"`
+}
+
+// nolint
+type DestinationRuleSubSet struct {
+ Name string `yaml:"name" json:"name"`
+ Labels map[string]string `yaml:"labels" json:"labels"`
+}
+
+// nolint
+func (urc *VirtualServiceConfig) DeepCopyObject() runtime.Object {
+ data, _ := yaml.Marshal(urc)
+ out := &VirtualServiceConfig{}
+ yaml.Unmarshal(data, out)
+ return out
+}
+
+// nolint
+type DestinationRuleSpecList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []DestinationRuleSpec `json:"items"`
+}
+
+// nolint
+type VirtualServiceConfigList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []VirtualServiceConfig `json:"items"`
+}
+
+// nolint
+func (drc *VirtualServiceConfigList) DeepCopyObject() runtime.Object {
+ out := &VirtualServiceConfigList{
+ TypeMeta: drc.TypeMeta,
+ ListMeta: drc.ListMeta,
+ }
+ for _, v := range drc.Items {
+ spec := v.DeepCopyObject().(*VirtualServiceConfig)
+ out.Items = append(out.Items, *spec)
+ }
+ return out
+}
+
+// nolint
+type DestinationRuleConfigList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []DestinationRuleConfig `json:"items"`
+}
+
+// nolint
+func (drc *DestinationRuleConfigList) DeepCopyObject() runtime.Object {
+ out := &DestinationRuleConfigList{
+ TypeMeta: drc.TypeMeta,
+ ListMeta: drc.ListMeta,
+ }
+ for _, v := range drc.Items {
+ spec := v.DeepCopyObject().(*DestinationRuleConfig)
+ out.Items = append(out.Items, *spec)
+ }
+ return out
+}
diff --git a/go.mod b/go.mod
index b505156..ebe4b7f 100644
--- a/go.mod
+++ b/go.mod
@@ -16,11 +16,12 @@ require (
github.com/docker/go-connections v0.4.0 // indirect
github.com/dubbogo/go-zookeeper v1.0.3
github.com/dubbogo/gost v1.11.8
- github.com/dubbogo/triple v0.1.3
+ github.com/dubbogo/triple v1.0.0
github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
github.com/emicklei/go-restful/v3 v3.4.0
github.com/frankban/quicktest v1.4.1 // indirect
github.com/fsnotify/fsnotify v1.4.9
+ github.com/ghodss/yaml v1.0.0
github.com/go-co-op/gocron v0.1.1
github.com/go-resty/resty/v2 v2.3.0
github.com/golang/mock v1.4.4
diff --git a/go.sum b/go.sum
index e280dc9..f672271 100644
--- a/go.sum
+++ b/go.sum
@@ -150,7 +150,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -188,8 +187,8 @@ github.com/dubbogo/gost v1.11.8/go.mod h1:2nB8jSrxVPwW5DBsRu3FZQH1+Ual3wnRHwFqjG
github.com/dubbogo/jsonparser v1.0.1/go.mod h1:tYAtpctvSP/tWw4MeelsowSPgXQRVHHWbqL6ynps8jU=
github.com/dubbogo/net v0.0.2-0.20210326124702-e6a866993192 h1:CBEicrrVwR6u8ty+kL68ItxXVk1jaVYThrsx5ARhxUc=
github.com/dubbogo/net v0.0.2-0.20210326124702-e6a866993192/go.mod h1:B6/ka3g8VzcyrmdCH4VkHP1K0aHeI37FmclS+TCwIBU=
-github.com/dubbogo/triple v0.1.3 h1:Tn+oK49JhSN1iOCRxT1DuKZJOPeySV0zc6ap+g3xjts=
-github.com/dubbogo/triple v0.1.3/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
+github.com/dubbogo/triple v1.0.0 h1:mbFU078PmyjO8OywtrNsTZW0RSYIImVGyXE4wLO3Vm0=
+github.com/dubbogo/triple v1.0.0/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -226,6 +225,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
@@ -820,7 +820,6 @@ github.com/zouyx/agollo/v3 v3.4.5 h1:7YCxzY9ZYaH9TuVUBvmI6Tk0mwMggikah+cfbYogcHQ
github.com/zouyx/agollo/v3 v3.4.5/go.mod h1:LJr3kDmm23QSW+F1Ol4TMHDa7HvJvscMdVxJ2IpUTVc=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 h1:jWtjCJX1qxhHISBMLRztWwR+EXkI7MJAF2HjHAE/x/I=
diff --git a/test/integrate/dubbo/go-client/go.sum b/test/integrate/dubbo/go-client/go.sum
index 75949aa..114d619 100644
--- a/test/integrate/dubbo/go-client/go.sum
+++ b/test/integrate/dubbo/go-client/go.sum
@@ -153,12 +153,14 @@ github.com/dubbogo/gost v1.11.3/go.mod h1:3QQEj50QOhkWTERT785YZ5ZxIRGNdR11FCLP7F
github.com/dubbogo/gost v1.11.5/go.mod h1:Q//0o51ooLfwpWzZMftJLvIitNEZXH3rRKkxdu37xJg=
github.com/dubbogo/gost v1.11.6/go.mod h1:Q//0o51ooLfwpWzZMftJLvIitNEZXH3rRKkxdu37xJg=
github.com/dubbogo/gost v1.11.7/go.mod h1:2nB8jSrxVPwW5DBsRu3FZQH1+Ual3wnRHwFqjG9+4PY=
+github.com/dubbogo/gost v1.11.8/go.mod h1:2nB8jSrxVPwW5DBsRu3FZQH1+Ual3wnRHwFqjG9+4PY=
github.com/dubbogo/jsonparser v1.0.1/go.mod h1:tYAtpctvSP/tWw4MeelsowSPgXQRVHHWbqL6ynps8jU=
github.com/dubbogo/net v0.0.2-0.20210326124702-e6a866993192/go.mod h1:B6/ka3g8VzcyrmdCH4VkHP1K0aHeI37FmclS+TCwIBU=
github.com/dubbogo/triple v0.0.0-20210403061850-372f2dc47e02/go.mod h1:ArB/FJCvy6DQXs8tW6LmNRtLaZuncGmDHqD/1JOAwsU=
github.com/dubbogo/triple v0.1.0/go.mod h1:ArB/FJCvy6DQXs8tW6LmNRtLaZuncGmDHqD/1JOAwsU=
github.com/dubbogo/triple v0.1.2/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
github.com/dubbogo/triple v0.1.3/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
+github.com/dubbogo/triple v1.0.0/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
github.com/dubbogo/v3router v0.0.0-20210403094230-574be83d8d6d/go.mod h1:prAeY9nOJfo09GBDh5DMV4khJhQOhy5JnLdMCzVk18c=
github.com/dubbogo/v3router v0.1.0/go.mod h1:lJ2qS8FLme8RXE8hq4kKdh/6aRi2sRq5MilrITnNxcE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
diff --git a/test/integrate/dubbo/go-server/go.sum b/test/integrate/dubbo/go-server/go.sum
index 75949aa..114d619 100644
--- a/test/integrate/dubbo/go-server/go.sum
+++ b/test/integrate/dubbo/go-server/go.sum
@@ -153,12 +153,14 @@ github.com/dubbogo/gost v1.11.3/go.mod h1:3QQEj50QOhkWTERT785YZ5ZxIRGNdR11FCLP7F
github.com/dubbogo/gost v1.11.5/go.mod h1:Q//0o51ooLfwpWzZMftJLvIitNEZXH3rRKkxdu37xJg=
github.com/dubbogo/gost v1.11.6/go.mod h1:Q//0o51ooLfwpWzZMftJLvIitNEZXH3rRKkxdu37xJg=
github.com/dubbogo/gost v1.11.7/go.mod h1:2nB8jSrxVPwW5DBsRu3FZQH1+Ual3wnRHwFqjG9+4PY=
+github.com/dubbogo/gost v1.11.8/go.mod h1:2nB8jSrxVPwW5DBsRu3FZQH1+Ual3wnRHwFqjG9+4PY=
github.com/dubbogo/jsonparser v1.0.1/go.mod h1:tYAtpctvSP/tWw4MeelsowSPgXQRVHHWbqL6ynps8jU=
github.com/dubbogo/net v0.0.2-0.20210326124702-e6a866993192/go.mod h1:B6/ka3g8VzcyrmdCH4VkHP1K0aHeI37FmclS+TCwIBU=
github.com/dubbogo/triple v0.0.0-20210403061850-372f2dc47e02/go.mod h1:ArB/FJCvy6DQXs8tW6LmNRtLaZuncGmDHqD/1JOAwsU=
github.com/dubbogo/triple v0.1.0/go.mod h1:ArB/FJCvy6DQXs8tW6LmNRtLaZuncGmDHqD/1JOAwsU=
github.com/dubbogo/triple v0.1.2/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
github.com/dubbogo/triple v0.1.3/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
+github.com/dubbogo/triple v1.0.0/go.mod h1:duJFWIYOE+Ajxxvk+AOBpEBePFNnviJ52fveZ3vYA04=
github.com/dubbogo/v3router v0.0.0-20210403094230-574be83d8d6d/go.mod h1:prAeY9nOJfo09GBDh5DMV4khJhQOhy5JnLdMCzVk18c=
github.com/dubbogo/v3router v0.1.0/go.mod h1:lJ2qS8FLme8RXE8hq4kKdh/6aRi2sRq5MilrITnNxcE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=