mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 16:24:19 -04:00
Add new plugin: traffic
Traffic is a plugin that communicates via the xDS protocol to an Envoy control plane. Using the data from this control plane it hands out IP addresses. This allows you (via controlling the data in the control plane) to drain or send more traffic to specific endpoints. The plugin itself only acts upon this data; it doesn't do anything fancy by itself. Code used here is copied from grpc-go and other places, this is clearly marked in the source files. Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
130
plugin/traffic/traffic_test.go
Normal file
130
plugin/traffic/traffic_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package traffic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/test"
|
||||
"github.com/coredns/coredns/plugin/traffic/xds"
|
||||
|
||||
xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
||||
corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
|
||||
endpointpb "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
|
||||
"github.com/miekg/dns"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func TestTraffic(t *testing.T) {
|
||||
c, err := xds.New("127.0.0.1:0", "test-id", grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tr := &Traffic{c: c, origins: []string{"lb.example.org."}}
|
||||
|
||||
tests := []struct {
|
||||
cla *xdspb.ClusterLoadAssignment
|
||||
cluster string
|
||||
qtype uint16
|
||||
rcode int
|
||||
answer string // address value of the A/AAAA record.
|
||||
ns bool // should there be a ns section.
|
||||
}{
|
||||
{
|
||||
cla: &xdspb.ClusterLoadAssignment{},
|
||||
cluster: "web", qtype: dns.TypeA, rcode: dns.RcodeSuccess, ns: true,
|
||||
},
|
||||
{
|
||||
cla: &xdspb.ClusterLoadAssignment{},
|
||||
cluster: "web", qtype: dns.TypeSRV, rcode: dns.RcodeSuccess, ns: true,
|
||||
},
|
||||
{
|
||||
cla: &xdspb.ClusterLoadAssignment{},
|
||||
cluster: "does-not-exist", qtype: dns.TypeA, rcode: dns.RcodeNameError, ns: true},
|
||||
{
|
||||
cla: &xdspb.ClusterLoadAssignment{
|
||||
ClusterName: "web",
|
||||
Endpoints: endpoints([]EndpointHealth{{"127.0.0.1", corepb.HealthStatus_HEALTHY}}),
|
||||
},
|
||||
cluster: "web", qtype: dns.TypeA, rcode: dns.RcodeSuccess, answer: "127.0.0.1",
|
||||
},
|
||||
{
|
||||
cla: &xdspb.ClusterLoadAssignment{
|
||||
ClusterName: "web",
|
||||
Endpoints: endpoints([]EndpointHealth{{"127.0.0.1", corepb.HealthStatus_UNKNOWN}}),
|
||||
},
|
||||
cluster: "web", qtype: dns.TypeA, rcode: dns.RcodeSuccess, ns: true,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
for i, tc := range tests {
|
||||
a := xds.NewAssignment()
|
||||
a.SetClusterLoadAssignment("web", tc.cla) // web is our cluster
|
||||
c.SetAssignments(a)
|
||||
|
||||
m := new(dns.Msg)
|
||||
cl := dnsutil.Join(tc.cluster, tr.origins[0])
|
||||
m.SetQuestion(cl, tc.qtype)
|
||||
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
_, err := tr.ServeDNS(ctx, rec, m)
|
||||
if err != nil {
|
||||
t.Errorf("Test %d: Expected no error, but got %q", i, err)
|
||||
}
|
||||
if rec.Msg.Rcode != tc.rcode {
|
||||
t.Errorf("Test %d: Expected no rcode %d, but got %d", i, tc.rcode, rec.Msg.Rcode)
|
||||
}
|
||||
if tc.ns && len(rec.Msg.Ns) == 0 {
|
||||
t.Errorf("Test %d: Expected authority section, but got none", i)
|
||||
}
|
||||
if tc.answer != "" && len(rec.Msg.Answer) == 0 {
|
||||
t.Fatalf("Test %d: Expected answer section, but got none", i)
|
||||
}
|
||||
if tc.answer != "" {
|
||||
record := rec.Msg.Answer[0]
|
||||
addr := ""
|
||||
switch x := record.(type) {
|
||||
case *dns.A:
|
||||
addr = x.A.String()
|
||||
case *dns.AAAA:
|
||||
addr = x.AAAA.String()
|
||||
}
|
||||
if tc.answer != addr {
|
||||
t.Errorf("Test %d: Expected answer %s, but got %s", i, tc.answer, addr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type EndpointHealth struct {
|
||||
Address string
|
||||
Health corepb.HealthStatus
|
||||
}
|
||||
|
||||
func endpoints(e []EndpointHealth) []*endpointpb.LocalityLbEndpoints {
|
||||
ep := make([]*endpointpb.LocalityLbEndpoints, len(e))
|
||||
for i := range e {
|
||||
ep[i] = &endpointpb.LocalityLbEndpoints{
|
||||
LbEndpoints: []*endpointpb.LbEndpoint{{
|
||||
HostIdentifier: &endpointpb.LbEndpoint_Endpoint{
|
||||
Endpoint: &endpointpb.Endpoint{
|
||||
Address: &corepb.Address{
|
||||
Address: &corepb.Address_SocketAddress{
|
||||
SocketAddress: &corepb.SocketAddress{
|
||||
Address: e[i].Address,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HealthStatus: e[i].Health,
|
||||
}},
|
||||
}
|
||||
}
|
||||
return ep
|
||||
}
|
||||
Reference in New Issue
Block a user