From 76d056e7b1b36b20b8e9c76ee79b2d48d45c3a12 Mon Sep 17 00:00:00 2001 From: Laurence <45508533+LaurenceLiZhixin@users.noreply.github.com> Date: Sat, 8 May 2021 21:14:58 +0800 Subject: [PATCH] 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 +++ .../judger/attachment_match_judger.go | 82 ++++++ .../judger/attachment_match_judger_test.go | 49 ++++ .../v3router/judger/bool_match_judger.go | 37 +++ .../v3router/judger/bool_match_judger_test.go | 48 ++++ .../v3router/judger/double_match_judger.go | 49 ++++ .../judger/double_match_judger_test.go | 61 +++++ .../judger/double_range_match_judger.go | 39 +++ .../judger/double_range_match_judger_test.go | 47 ++++ .../judger/list_double_match_judger.go | 44 +++ .../judger/list_double_match_judger_test.go | 100 +++++++ .../judger/list_string_match_judger.go | 44 +++ .../v3router/judger/method_match_judger.go | 89 ++++++ .../v3router/judger/string_match_judger.go | 60 ++++ .../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 +++++++++ .../k8s_crd/deploy/unifom_router_crd.yml | 43 +++ .../v3router/k8s_crd/listener_handler.go | 35 +++ cluster/router/v3router/router_chain.go | 246 +++++++++++++++++ cluster/router/v3router/router_chain_test.go | 208 ++++++++++++++ .../router/v3router/test_file/dest_rule.yml | 17 ++ .../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(-) create mode 100644 cluster/router/v3router/dubbo_rule.go create mode 100644 cluster/router/v3router/factory.go create mode 100644 cluster/router/v3router/factory_test.go create mode 100644 cluster/router/v3router/judger/attachment_match_judger.go create mode 100644 cluster/router/v3router/judger/attachment_match_judger_test.go create mode 100644 cluster/router/v3router/judger/bool_match_judger.go create mode 100644 cluster/router/v3router/judger/bool_match_judger_test.go create mode 100644 cluster/router/v3router/judger/double_match_judger.go create mode 100644 cluster/router/v3router/judger/double_match_judger_test.go create mode 100644 cluster/router/v3router/judger/double_range_match_judger.go create mode 100644 cluster/router/v3router/judger/double_range_match_judger_test.go create mode 100644 cluster/router/v3router/judger/list_double_match_judger.go create mode 100644 cluster/router/v3router/judger/list_double_match_judger_test.go create mode 100644 cluster/router/v3router/judger/list_string_match_judger.go create mode 100644 cluster/router/v3router/judger/method_match_judger.go create mode 100644 cluster/router/v3router/judger/string_match_judger.go create mode 100644 cluster/router/v3router/judger/string_match_judger_test.go create mode 100644 cluster/router/v3router/judger/url_label_match_judge.go create mode 100644 cluster/router/v3router/k8s_api/k8s.go create mode 100644 cluster/router/v3router/k8s_api/listener_handler_impl.go create mode 100644 cluster/router/v3router/k8s_crd/client.go create mode 100644 cluster/router/v3router/k8s_crd/deploy/unifom_router_crd.yml create mode 100644 cluster/router/v3router/k8s_crd/listener_handler.go create mode 100644 cluster/router/v3router/router_chain.go create mode 100644 cluster/router/v3router/router_chain_test.go create mode 100644 cluster/router/v3router/test_file/dest_rule.yml create mode 100644 cluster/router/v3router/test_file/virtual_service.yml create mode 100644 cluster/router/v3router/uniform_route.go create mode 100644 cluster/router/v3router/uniform_rule.go create mode 100644 config/uniform_router_config.go diff --git a/cluster/router/v3router/dubbo_rule.go b/cluster/router/v3router/dubbo_rule.go new file mode 100644 index 0000000000..a77a13ecaa --- /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 0000000000..30b121c328 --- /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 0000000000..365d7552f4 --- /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 0000000000..7772a2d97e --- /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 0000000000..47dae98a31 --- /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 0000000000..da6bf8a238 --- /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 0000000000..1ed3e35cb1 --- /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 0000000000..b640d9468d --- /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 0000000000..4864b50905 --- /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 0000000000..3f3adc36db --- /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 0000000000..4e1926d8fb --- /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 0000000000..25feccd23d --- /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 0000000000..66d884fc89 --- /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 0000000000..e4f7cb7454 --- /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 0000000000..672a43af1b --- /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 0000000000..02b74b54a9 --- /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 0000000000..81c25e9213 --- /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 0000000000..bfb26e497e --- /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 0000000000..75e8a21542 --- /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 0000000000..b2f0206ece --- /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 0000000000..5634d68f10 --- /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 0000000000..9acc7d787e --- /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 0000000000..2a522918e1 --- /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 0000000000..4b03c1b714 --- /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 0000000000..4e05de9d1b --- /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 0000000000..89bd88f015 --- /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 0000000000..1c6b7513b1 --- /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 0000000000..c11c296eb0 --- /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 0000000000..f7e8148a61 --- /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 0000000000..e18c07c082 --- /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 b505156f77..ebe4b7fd12 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 e280dc9209..f672271e14 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 75949aafb6..114d619cbd 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 75949aafb6..114d619cbd 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=