mirror of https://github.com/linkerd/linkerd2.git
270 lines
8.3 KiB
Go
270 lines
8.3 KiB
Go
package destination
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
|
|
pb "github.com/linkerd/linkerd2-proxy-api/go/destination"
|
|
"github.com/linkerd/linkerd2-proxy-api/go/net"
|
|
"github.com/linkerd/linkerd2/controller/api/destination/watcher"
|
|
"github.com/linkerd/linkerd2/pkg/addr"
|
|
"github.com/linkerd/linkerd2/pkg/k8s"
|
|
logging "github.com/sirupsen/logrus"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
var (
|
|
normalPod = watcher.Address{
|
|
IP: "1.1.1.1",
|
|
Port: 1,
|
|
Pod: &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod1",
|
|
Namespace: "ns",
|
|
Annotations: map[string]string{
|
|
k8s.IdentityModeAnnotation: k8s.IdentityModeDefault,
|
|
},
|
|
Labels: map[string]string{
|
|
k8s.ControllerNSLabel: "linkerd",
|
|
k8s.ProxyDeploymentLabel: "deployment-name",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
ServiceAccountName: "serviceaccount-name",
|
|
},
|
|
},
|
|
OwnerKind: "replicationcontroller",
|
|
OwnerName: "rc-name",
|
|
}
|
|
|
|
tlsOptionalPod = watcher.Address{
|
|
IP: "1.1.1.2",
|
|
Port: 2,
|
|
Pod: &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod2",
|
|
Namespace: "ns",
|
|
Annotations: map[string]string{
|
|
k8s.IdentityModeAnnotation: "optional",
|
|
},
|
|
Labels: map[string]string{
|
|
k8s.ControllerNSLabel: "linkerd",
|
|
k8s.ProxyDeploymentLabel: "deployment-name",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
otherMeshPod = watcher.Address{
|
|
IP: "1.1.1.3",
|
|
Port: 3,
|
|
Pod: &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod3",
|
|
Namespace: "ns",
|
|
Annotations: map[string]string{
|
|
k8s.IdentityModeAnnotation: k8s.IdentityModeDefault,
|
|
},
|
|
Labels: map[string]string{
|
|
k8s.ControllerNSLabel: "other-linkerd-namespace",
|
|
k8s.ProxyDeploymentLabel: "deployment-name",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
tlsDisabledPod = watcher.Address{
|
|
IP: "1.1.1.4",
|
|
Port: 4,
|
|
Pod: &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod4",
|
|
Namespace: "ns",
|
|
Annotations: map[string]string{
|
|
k8s.IdentityModeAnnotation: k8s.IdentityModeDisabled,
|
|
},
|
|
Labels: map[string]string{
|
|
k8s.ControllerNSLabel: "linkerd",
|
|
k8s.ProxyDeploymentLabel: "deployment-name",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
func makeEndpointTranslator(t *testing.T) (*mockDestinationGetServer, *endpointTranslator) {
|
|
mockGetServer := &mockDestinationGetServer{updatesReceived: []*pb.Update{}}
|
|
translator := newEndpointTranslator(
|
|
"linkerd",
|
|
"trust.domain",
|
|
false,
|
|
watcher.ServiceID{Name: "service-name", Namespace: "service-ns"},
|
|
mockGetServer,
|
|
logging.WithField("test", t.Name),
|
|
)
|
|
return mockGetServer, translator
|
|
}
|
|
|
|
func TestEndpointTranslator(t *testing.T) {
|
|
t.Run("Sends one update for add and another for remove", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(normalPod))
|
|
translator.Remove(mkPodSet(tlsOptionalPod))
|
|
|
|
expectedNumUpdates := 2
|
|
actualNumUpdates := len(mockGetServer.updatesReceived)
|
|
if actualNumUpdates != expectedNumUpdates {
|
|
t.Fatalf("Expecting [%d] updates, got [%d]. Updates: %v", expectedNumUpdates, actualNumUpdates, mockGetServer.updatesReceived)
|
|
}
|
|
})
|
|
|
|
t.Run("Sends addresses as removed or added", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(normalPod, tlsOptionalPod))
|
|
translator.Remove(mkPodSet(tlsDisabledPod))
|
|
|
|
addressesAdded := mockGetServer.updatesReceived[0].GetAdd().Addrs
|
|
actualNumberOfAdded := len(addressesAdded)
|
|
expectedNumberOfAdded := 2
|
|
if actualNumberOfAdded != expectedNumberOfAdded {
|
|
t.Fatalf("Expecting [%d] addresses to be added, got [%d]: %v", expectedNumberOfAdded, actualNumberOfAdded, addressesAdded)
|
|
}
|
|
|
|
addressesRemoved := mockGetServer.updatesReceived[1].GetRemove().Addrs
|
|
actualNumberOfRemoved := len(addressesRemoved)
|
|
expectedNumberOfRemoved := 1
|
|
if actualNumberOfRemoved != expectedNumberOfRemoved {
|
|
t.Fatalf("Expecting [%d] addresses to be removed, got [%d]: %v", expectedNumberOfRemoved, actualNumberOfRemoved, addressesRemoved)
|
|
}
|
|
|
|
sort.Slice(addressesAdded, func(i, j int) bool {
|
|
return addressesAdded[i].GetAddr().Port < addressesAdded[j].GetAddr().Port
|
|
})
|
|
checkAddressAndWeight(t, addressesAdded[0], normalPod)
|
|
checkAddressAndWeight(t, addressesAdded[1], tlsOptionalPod)
|
|
checkAddress(t, addressesRemoved[0], tlsDisabledPod)
|
|
})
|
|
|
|
t.Run("Sends metric labels with added addresses", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(normalPod))
|
|
|
|
actualGlobalMetricLabels := mockGetServer.updatesReceived[0].GetAdd().MetricLabels
|
|
expectedGlobalMetricLabels := map[string]string{"namespace": "service-ns", "service": "service-name"}
|
|
if !reflect.DeepEqual(actualGlobalMetricLabels, expectedGlobalMetricLabels) {
|
|
t.Fatalf("Expected global metric labels sent to be [%v] but was [%v]", expectedGlobalMetricLabels, actualGlobalMetricLabels)
|
|
}
|
|
|
|
actualAddedAddress1MetricLabels := mockGetServer.updatesReceived[0].GetAdd().Addrs[0].MetricLabels
|
|
expectedAddedAddress1MetricLabels := map[string]string{
|
|
"pod": "pod1",
|
|
"replicationcontroller": "rc-name",
|
|
"serviceaccount": "serviceaccount-name",
|
|
"control_plane_ns": "linkerd",
|
|
}
|
|
if !reflect.DeepEqual(actualAddedAddress1MetricLabels, expectedAddedAddress1MetricLabels) {
|
|
t.Fatalf("Expected global metric labels sent to be [%v] but was [%v]", expectedAddedAddress1MetricLabels, actualAddedAddress1MetricLabels)
|
|
}
|
|
})
|
|
|
|
t.Run("Sends TlsIdentity when enabled", func(t *testing.T) {
|
|
expectedTLSIdentity := &pb.TlsIdentity_DnsLikeIdentity{
|
|
Name: "serviceaccount-name.ns.serviceaccount.identity.linkerd.trust.domain",
|
|
}
|
|
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(normalPod))
|
|
|
|
addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
|
|
if len(addrs) != 1 {
|
|
t.Fatalf("Expected [1] address returned, got %v", addrs)
|
|
}
|
|
|
|
actualTLSIdentity := addrs[0].GetTlsIdentity().GetDnsLikeIdentity()
|
|
if !reflect.DeepEqual(actualTLSIdentity, expectedTLSIdentity) {
|
|
t.Fatalf("Expected TlsIdentity to be [%v] but was [%v]", expectedTLSIdentity, actualTLSIdentity)
|
|
}
|
|
})
|
|
|
|
t.Run("Does not send TlsIdentity for non-default identity-modes", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(tlsOptionalPod))
|
|
|
|
addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
|
|
if len(addrs) != 1 {
|
|
t.Fatalf("Expected [1] address returned, got %v", addrs)
|
|
}
|
|
|
|
if addrs[0].TlsIdentity != nil {
|
|
t.Fatalf("Expected no TlsIdentity to be sent, but got [%v]", addrs[0].TlsIdentity)
|
|
}
|
|
})
|
|
|
|
t.Run("Does not send TlsIdentity for other meshes", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(otherMeshPod))
|
|
|
|
addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
|
|
if len(addrs) != 1 {
|
|
t.Fatalf("Expected [1] address returned, got %v", addrs)
|
|
}
|
|
|
|
if addrs[0].TlsIdentity != nil {
|
|
t.Fatalf("Expected no TlsIdentity to be sent, but got [%v]", addrs[0].TlsIdentity)
|
|
}
|
|
})
|
|
|
|
t.Run("Does not send TlsIdentity when not enabled", func(t *testing.T) {
|
|
mockGetServer, translator := makeEndpointTranslator(t)
|
|
|
|
translator.Add(mkPodSet(tlsDisabledPod))
|
|
|
|
addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
|
|
if len(addrs) != 1 {
|
|
t.Fatalf("Expected [1] address returned, got %v", addrs)
|
|
}
|
|
|
|
if addrs[0].TlsIdentity != nil {
|
|
t.Fatalf("Expected no TlsIdentity to be sent, but got [%v]", addrs[0].TlsIdentity)
|
|
}
|
|
})
|
|
}
|
|
|
|
func mkPodSet(pods ...watcher.Address) watcher.PodSet {
|
|
set := make(watcher.PodSet)
|
|
for _, p := range pods {
|
|
id := watcher.PodID{Name: p.Pod.Name, Namespace: p.Pod.Namespace}
|
|
set[id] = p
|
|
}
|
|
return set
|
|
}
|
|
|
|
func checkAddressAndWeight(t *testing.T, actual *pb.WeightedAddr, expected watcher.Address) {
|
|
checkAddress(t, actual.GetAddr(), expected)
|
|
if actual.GetWeight() != defaultWeight {
|
|
t.Fatalf("Expected weight [%+v] but got [%+v]", defaultWeight, actual.GetWeight())
|
|
}
|
|
}
|
|
|
|
func checkAddress(t *testing.T, actual *net.TcpAddress, expected watcher.Address) {
|
|
expectedAddr, err := addr.ParseProxyIPV4(expected.IP)
|
|
expectedTCP := net.TcpAddress{
|
|
Ip: expectedAddr,
|
|
Port: expected.Port,
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse expected IP [%s]: %s", expected.IP, err)
|
|
}
|
|
if !reflect.DeepEqual(*actual, expectedTCP) {
|
|
t.Fatalf("Expected address [%+v] but got [%+v]", expectedTCP, *actual)
|
|
}
|
|
}
|