linkerd2/pkg/inject/report_test.go

426 lines
10 KiB
Go

package inject
import (
"fmt"
"testing"
"github.com/linkerd/linkerd2/pkg/k8s"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestInjectable(t *testing.T) {
var testCases = []struct {
podSpec *corev1.PodSpec
podMeta *metav1.ObjectMeta
nsAnnotations map[string]string
unsupportedResource bool
injectable bool
reasons []string
}{
{
podSpec: &corev1.PodSpec{
HostNetwork: false,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: true,
},
{
podSpec: &corev1.PodSpec{
HostNetwork: true,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: false,
reasons: []string{hostNetworkEnabled},
},
{
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{
Name: k8s.ProxyContainerName,
Image: "cr.l5d.io/linkerd/proxy:",
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: false,
reasons: []string{sidecarExists},
},
{
podSpec: &corev1.PodSpec{
InitContainers: []corev1.Container{
{
Name: k8s.InitContainerName,
Image: "cr.l5d.io/linkerd/proxy-init:",
},
},
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: false,
reasons: []string{sidecarExists},
},
{
unsupportedResource: true,
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: false,
reasons: []string{unsupportedResource},
},
{
unsupportedResource: true,
podSpec: &corev1.PodSpec{
HostNetwork: true,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
injectable: false,
reasons: []string{hostNetworkEnabled, unsupportedResource},
},
{
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
podSpec: &corev1.PodSpec{
HostNetwork: true,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
injectable: false,
reasons: []string{hostNetworkEnabled, injectDisableAnnotationPresent},
},
{
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
unsupportedResource: true,
podSpec: &corev1.PodSpec{
HostNetwork: true,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
injectable: false,
reasons: []string{hostNetworkEnabled, unsupportedResource, injectDisableAnnotationPresent},
},
{
unsupportedResource: true,
podSpec: &corev1.PodSpec{
HostNetwork: true,
Containers: []corev1.Container{
{
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
},
},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{},
},
injectable: false,
reasons: []string{hostNetworkEnabled, unsupportedResource, injectEnableAnnotationAbsent},
},
{
podSpec: &corev1.PodSpec{HostNetwork: true,
Containers: []corev1.Container{
{
Name: k8s.ProxyContainerName,
Image: "cr.l5d.io/linkerd/proxy:",
VolumeMounts: []corev1.VolumeMount{
{
MountPath: k8s.MountPathServiceAccount,
},
},
},
}},
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{},
},
injectable: false,
reasons: []string{hostNetworkEnabled, sidecarExists, injectEnableAnnotationAbsent},
},
}
for i, testCase := range testCases {
testCase := testCase
t.Run(fmt.Sprintf("test case #%d", i), func(t *testing.T) {
resourceConfig := &ResourceConfig{}
resourceConfig.WithNsAnnotations(testCase.nsAnnotations)
resourceConfig.pod.spec = testCase.podSpec
resourceConfig.origin = OriginWebhook
resourceConfig.pod.meta = testCase.podMeta
report := newReport(resourceConfig)
report.UnsupportedResource = testCase.unsupportedResource
actual, reasons := report.Injectable()
if testCase.injectable != actual {
t.Errorf("Expected %t. Actual %t", testCase.injectable, actual)
}
if len(reasons) != len(testCase.reasons) {
t.Errorf("Expected %d number of reasons. Actual %d", len(testCase.reasons), len(reasons))
}
for i := range reasons {
if testCase.reasons[i] != reasons[i] {
t.Errorf("Expected reason '%s'. Actual reason '%s'", testCase.reasons[i], reasons[i])
}
}
})
}
}
func TestDisableByAnnotation(t *testing.T) {
t.Run("webhook origin", func(t *testing.T) {
var testCases = []struct {
podMeta *metav1.ObjectMeta
nsAnnotations map[string]string
expected bool
}{
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
expected: true,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
expected: true,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
nsAnnotations: map[string]string{},
expected: true,
},
{
podMeta: &metav1.ObjectMeta{},
nsAnnotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
expected: true,
},
{
podMeta: &metav1.ObjectMeta{},
nsAnnotations: map[string]string{},
expected: true,
},
}
for i, testCase := range testCases {
testCase := testCase
t.Run(fmt.Sprintf("test case #%d", i), func(t *testing.T) {
resourceConfig := &ResourceConfig{origin: OriginWebhook}
resourceConfig.WithNsAnnotations(testCase.nsAnnotations)
resourceConfig.pod.meta = testCase.podMeta
resourceConfig.pod.spec = &corev1.PodSpec{} // initialize empty spec to prevent test from failing
report := newReport(resourceConfig)
if actual, _, _ := report.disabledByAnnotation(resourceConfig); testCase.expected != actual {
t.Errorf("Expected %t. Actual %t", testCase.expected, actual)
}
})
}
})
t.Run("CLI origin", func(t *testing.T) {
var testCases = []struct {
podMeta *metav1.ObjectMeta
expected bool
}{
{
podMeta: &metav1.ObjectMeta{},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
},
},
expected: false,
},
{
podMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyInjectAnnotation: k8s.ProxyInjectDisabled,
},
},
expected: true,
},
}
for i, testCase := range testCases {
testCase := testCase
t.Run(fmt.Sprintf("test case #%d", i), func(t *testing.T) {
resourceConfig := &ResourceConfig{origin: OriginCLI}
resourceConfig.pod.meta = testCase.podMeta
resourceConfig.pod.spec = &corev1.PodSpec{} // initialize empty spec to prevent test from failing
report := newReport(resourceConfig)
if actual, _, _ := report.disabledByAnnotation(resourceConfig); testCase.expected != actual {
t.Errorf("Expected %t. Actual %t", testCase.expected, actual)
}
})
}
})
}