blob: dfbf56d81406254eb5ba9cdd4df3f8bd19c4e066 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed 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 server_test
import (
"testing"
)
import (
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/testing/protocmp"
meshconfig "istio.io/api/mesh/v1alpha1"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/model"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/serviceregistry/provider"
"github.com/apache/dubbo-go-pixiu/pkg/config/constants"
"github.com/apache/dubbo-go-pixiu/pkg/config/host"
"github.com/apache/dubbo-go-pixiu/pkg/config/protocol"
dnsProto "github.com/apache/dubbo-go-pixiu/pkg/dns/proto"
dnsServer "github.com/apache/dubbo-go-pixiu/pkg/dns/server"
)
// nolint
func makeServiceInstances(proxy *model.Proxy, service *model.Service, hostname, subdomain string) map[int][]*model.ServiceInstance {
instances := make(map[int][]*model.ServiceInstance)
for _, port := range service.Ports {
instances[port.Port] = makeInstances(proxy, service, port.Port, port.Port)
instances[port.Port][0].Endpoint.HostName = hostname
instances[port.Port][0].Endpoint.SubDomain = subdomain
instances[port.Port][0].Endpoint.Network = proxy.Metadata.Network
instances[port.Port][0].Endpoint.Locality.ClusterID = proxy.Metadata.ClusterID
}
return instances
}
func TestNameTable(t *testing.T) {
mesh := &meshconfig.MeshConfig{RootNamespace: "dubbo-system"}
proxy := &model.Proxy{
IPAddresses: []string{"9.9.9.9"},
Metadata: &model.NodeMetadata{},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
nw1proxy := &model.Proxy{
IPAddresses: []string{"9.9.9.9"},
Metadata: &model.NodeMetadata{Network: "nw1"},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
cl1proxy := &model.Proxy{
IPAddresses: []string{"9.9.9.9"},
Metadata: &model.NodeMetadata{ClusterID: "cl1"},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
pod1 := &model.Proxy{
IPAddresses: []string{"1.2.3.4"},
Metadata: &model.NodeMetadata{},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
pod2 := &model.Proxy{
IPAddresses: []string{"9.6.7.8"},
Metadata: &model.NodeMetadata{Network: "nw2", ClusterID: "cl2"},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
pod3 := &model.Proxy{
IPAddresses: []string{"19.6.7.8"},
Metadata: &model.NodeMetadata{Network: "nw1"},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
pod4 := &model.Proxy{
IPAddresses: []string{"9.16.7.8"},
Metadata: &model.NodeMetadata{ClusterID: "cl1"},
Type: model.SidecarProxy,
DNSDomain: "testns.svc.cluster.local",
}
headlessService := &model.Service{
Hostname: host.Name("headless-svc.testns.svc.cluster.local"),
DefaultAddress: constants.UnspecifiedIP,
Ports: model.PortList{&model.Port{
Name: "tcp-port",
Port: 9000,
Protocol: protocol.TCP,
}},
Resolution: model.Passthrough,
Attributes: model.ServiceAttributes{
Name: "headless-svc",
Namespace: "testns",
ServiceRegistry: provider.Kubernetes,
},
}
headlessServiceForServiceEntry := &model.Service{
Hostname: host.Name("foo.bar.com"),
DefaultAddress: constants.UnspecifiedIP,
Ports: model.PortList{&model.Port{
Name: "tcp-port",
Port: 9000,
Protocol: protocol.TCP,
}},
Resolution: model.Passthrough,
Attributes: model.ServiceAttributes{
Name: "foo.bar.com",
Namespace: "testns",
ServiceRegistry: provider.External,
LabelSelectors: map[string]string{"wl": "headless-foobar"},
},
}
wildcardService := &model.Service{
Hostname: host.Name("*.testns.svc.cluster.local"),
DefaultAddress: "172.10.10.10",
Ports: model.PortList{
&model.Port{
Name: "tcp-port",
Port: 9000,
Protocol: protocol.TCP,
},
&model.Port{
Name: "http-port",
Port: 8000,
Protocol: protocol.HTTP,
},
},
Resolution: model.ClientSideLB,
Attributes: model.ServiceAttributes{
Name: "wildcard-svc",
Namespace: "testns",
ServiceRegistry: provider.Kubernetes,
},
}
cidrService := &model.Service{
Hostname: host.Name("*.testns.svc.cluster.local"),
DefaultAddress: "172.217.0.0/16",
Ports: model.PortList{
&model.Port{
Name: "tcp-port",
Port: 9000,
Protocol: protocol.TCP,
},
&model.Port{
Name: "http-port",
Port: 8000,
Protocol: protocol.HTTP,
},
},
Resolution: model.ClientSideLB,
Attributes: model.ServiceAttributes{
Name: "cidr-svc",
Namespace: "testns",
ServiceRegistry: provider.Kubernetes,
},
}
push := model.NewPushContext()
push.Mesh = mesh
push.AddPublicServices([]*model.Service{headlessService})
push.AddServiceInstances(headlessService,
makeServiceInstances(pod1, headlessService, "pod1", "headless-svc"))
push.AddServiceInstances(headlessService,
makeServiceInstances(pod2, headlessService, "pod2", "headless-svc"))
push.AddServiceInstances(headlessService,
makeServiceInstances(pod3, headlessService, "pod3", "headless-svc"))
push.AddServiceInstances(headlessService,
makeServiceInstances(pod4, headlessService, "pod4", "headless-svc"))
wpush := model.NewPushContext()
wpush.Mesh = mesh
wpush.AddPublicServices([]*model.Service{wildcardService})
cpush := model.NewPushContext()
cpush.Mesh = mesh
wpush.AddPublicServices([]*model.Service{cidrService})
sepush := model.NewPushContext()
sepush.Mesh = mesh
sepush.AddPublicServices([]*model.Service{headlessServiceForServiceEntry})
sepush.AddServiceInstances(headlessServiceForServiceEntry,
makeServiceInstances(pod1, headlessServiceForServiceEntry, "", ""))
sepush.AddServiceInstances(headlessServiceForServiceEntry,
makeServiceInstances(pod2, headlessServiceForServiceEntry, "", ""))
sepush.AddServiceInstances(headlessServiceForServiceEntry,
makeServiceInstances(pod3, headlessServiceForServiceEntry, "", ""))
sepush.AddServiceInstances(headlessServiceForServiceEntry,
makeServiceInstances(pod4, headlessServiceForServiceEntry, "", ""))
cases := []struct {
name string
proxy *model.Proxy
push *model.PushContext
enableMultiClusterHeadless bool
expectedNameTable *dnsProto.NameTable
}{
{
name: "headless service pods",
proxy: proxy,
push: push,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"pod1.headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4"},
Registry: "Kubernetes",
Shortname: "pod1.headless-svc",
Namespace: "testns",
},
"pod2.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod2.headless-svc",
Namespace: "testns",
},
"pod3.headless-svc.testns.svc.cluster.local": {
Ips: []string{"19.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod3.headless-svc",
Namespace: "testns",
},
"pod4.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.16.7.8"},
Registry: "Kubernetes",
Shortname: "pod4.headless-svc",
Namespace: "testns",
},
"headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4", "9.6.7.8", "19.6.7.8", "9.16.7.8"},
Registry: "Kubernetes",
Shortname: "headless-svc",
Namespace: "testns",
},
},
},
},
{
name: "headless service pods with network isolation",
proxy: nw1proxy,
push: push,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"pod1.headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4"},
Registry: "Kubernetes",
Shortname: "pod1.headless-svc",
Namespace: "testns",
},
"pod3.headless-svc.testns.svc.cluster.local": {
Ips: []string{"19.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod3.headless-svc",
Namespace: "testns",
},
"pod4.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.16.7.8"},
Registry: "Kubernetes",
Shortname: "pod4.headless-svc",
Namespace: "testns",
},
"headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
Registry: "Kubernetes",
Shortname: "headless-svc",
Namespace: "testns",
},
},
},
},
{
name: "multi cluster headless service pods",
proxy: cl1proxy,
push: push,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"pod1.headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4"},
Registry: "Kubernetes",
Shortname: "pod1.headless-svc",
Namespace: "testns",
},
"pod2.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod2.headless-svc",
Namespace: "testns",
},
"pod3.headless-svc.testns.svc.cluster.local": {
Ips: []string{"19.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod3.headless-svc",
Namespace: "testns",
},
"pod4.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.16.7.8"},
Registry: "Kubernetes",
Shortname: "pod4.headless-svc",
Namespace: "testns",
},
"headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
Registry: "Kubernetes",
Shortname: "headless-svc",
Namespace: "testns",
},
},
},
},
{
name: "multi cluster headless service pods with multi cluster enabled",
proxy: cl1proxy,
push: push,
enableMultiClusterHeadless: true,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"pod1.headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4"},
Registry: "Kubernetes",
Shortname: "pod1.headless-svc",
Namespace: "testns",
},
"pod2.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod2.headless-svc",
Namespace: "testns",
},
"pod3.headless-svc.testns.svc.cluster.local": {
Ips: []string{"19.6.7.8"},
Registry: "Kubernetes",
Shortname: "pod3.headless-svc",
Namespace: "testns",
},
"pod4.headless-svc.testns.svc.cluster.local": {
Ips: []string{"9.16.7.8"},
Registry: "Kubernetes",
Shortname: "pod4.headless-svc",
Namespace: "testns",
},
"headless-svc.testns.svc.cluster.local": {
Ips: []string{"1.2.3.4", "9.6.7.8", "19.6.7.8", "9.16.7.8"},
Registry: "Kubernetes",
Shortname: "headless-svc",
Namespace: "testns",
},
},
},
},
{
name: "wildcard service pods",
proxy: proxy,
push: wpush,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"*.testns.svc.cluster.local": {
Ips: []string{"172.10.10.10"},
Registry: "Kubernetes",
Shortname: "wildcard-svc",
Namespace: "testns",
},
},
},
},
{
name: "cidr service",
proxy: proxy,
push: cpush,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{},
},
},
{
name: "service entry with resolution = NONE",
proxy: proxy,
push: sepush,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"foo.bar.com": {
Ips: []string{"1.2.3.4", "9.6.7.8", "19.6.7.8", "9.16.7.8"},
Registry: "External",
},
},
},
},
{
name: "service entry with resolution = NONE with network isolation",
proxy: nw1proxy,
push: sepush,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"foo.bar.com": {
Ips: []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
Registry: "External",
},
},
},
},
{
name: "multi cluster service entry with resolution = NONE",
proxy: cl1proxy,
push: sepush,
expectedNameTable: &dnsProto.NameTable{
Table: map[string]*dnsProto.NameTable_NameInfo{
"foo.bar.com": {
Ips: []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
Registry: "External",
},
},
},
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
tt.proxy.SidecarScope = model.ConvertToSidecarScope(tt.push, nil, "default")
if diff := cmp.Diff(dnsServer.BuildNameTable(dnsServer.Config{
Node: tt.proxy,
Push: tt.push,
MulticlusterHeadlessEnabled: tt.enableMultiClusterHeadless,
}), tt.expectedNameTable, protocmp.Transform()); diff != "" {
t.Fatalf("got diff: %v", diff)
}
})
}
}
func makeInstances(proxy *model.Proxy, svc *model.Service, servicePort int, targetPort int) []*model.ServiceInstance {
ret := make([]*model.ServiceInstance, 0)
for _, p := range svc.Ports {
if p.Port != servicePort {
continue
}
ret = append(ret, &model.ServiceInstance{
Service: svc,
ServicePort: p,
Endpoint: &model.IstioEndpoint{
Address: proxy.IPAddresses[0],
ServicePortName: p.Name,
EndpointPort: uint32(targetPort),
},
})
}
return ret
}