linkerd2/pkg/inject/inject_test.go

368 lines
14 KiB
Go

package inject
import (
"testing"
"github.com/go-test/deep"
l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/linkerd/linkerd2/pkg/util"
"github.com/linkerd/linkerd2/pkg/version"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
k8sResource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
func TestGetOverriddenValues(t *testing.T) {
// this test uses an annotated deployment and a expected Values object to verify
// the GetOverriddenValues function.
var (
proxyVersionOverride = "proxy-version-override"
pullPolicy = "Always"
)
testConfig, err := l5dcharts.NewValues()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
var testCases = []struct {
id string
nsAnnotations map[string]string
spec appsv1.DeploymentSpec
expected func() *l5dcharts.Values
}{
{id: "use overrides",
nsAnnotations: make(map[string]string),
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyImageAnnotation: "cr.l5d.io/linkerd/proxy",
k8s.ProxyImagePullPolicyAnnotation: pullPolicy,
k8s.ProxyInitImageAnnotation: "cr.l5d.io/linkerd/proxy-init",
k8s.ProxyControlPortAnnotation: "4000",
k8s.ProxyInboundPortAnnotation: "5000",
k8s.ProxyAdminPortAnnotation: "5001",
k8s.ProxyOutboundPortAnnotation: "5002",
k8s.ProxyPodInboundPortsAnnotation: "1234,5678",
k8s.ProxyIgnoreInboundPortsAnnotation: "4222,6222",
k8s.ProxyIgnoreOutboundPortsAnnotation: "8079,8080",
k8s.ProxyCPURequestAnnotation: "0.15",
k8s.ProxyMemoryRequestAnnotation: "120",
k8s.ProxyEphemeralStorageRequestAnnotation: "10",
k8s.ProxyCPULimitAnnotation: "1.5",
k8s.ProxyMemoryLimitAnnotation: "256",
k8s.ProxyEphemeralStorageLimitAnnotation: "50",
k8s.ProxyUIDAnnotation: "8500",
k8s.ProxyGIDAnnotation: "8500",
k8s.ProxyLogLevelAnnotation: "debug,linkerd=debug",
k8s.ProxyLogFormatAnnotation: "json",
k8s.ProxyEnableExternalProfilesAnnotation: "false",
k8s.ProxyVersionOverrideAnnotation: proxyVersionOverride,
k8s.ProxyWaitBeforeExitSecondsAnnotation: "123",
k8s.ProxyRequireIdentityOnInboundPortsAnnotation: "8888,9999",
k8s.ProxyOutboundConnectTimeout: "6000ms",
k8s.ProxyInboundConnectTimeout: "600ms",
k8s.ProxyOpaquePortsAnnotation: "4320-4325,3306",
k8s.ProxyAwait: "enabled",
k8s.ProxySkipSubnetsAnnotation: "172.17.0.0/16",
k8s.ProxyAccessLogAnnotation: "apache",
k8s.ProxyShutdownGracePeriodAnnotation: "30s",
k8s.ProxyOutboundDiscoveryCacheUnusedTimeout: "50000ms",
k8s.ProxyInboundDiscoveryCacheUnusedTimeout: "900s",
k8s.ProxyDisableOutboundProtocolDetectTimeout: "true",
k8s.ProxyDisableInboundProtocolDetectTimeout: "true",
k8s.ProxyEnableNativeSidecarAnnotation: "true",
},
},
Spec: corev1.PodSpec{},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
values.Proxy.Runtime.Workers.Maximum = 2
values.Proxy.Image.Name = "cr.l5d.io/linkerd/proxy"
values.Proxy.Image.PullPolicy = pullPolicy
values.Proxy.Image.Version = proxyVersionOverride
values.Proxy.PodInboundPorts = "1234,5678"
values.Proxy.Ports.Control = 4000
values.Proxy.Ports.Inbound = 5000
values.Proxy.Ports.Admin = 5001
values.Proxy.Ports.Outbound = 5002
values.Proxy.WaitBeforeExitSeconds = 123
values.Proxy.LogLevel = "debug,linkerd=debug"
values.Proxy.LogFormat = "json"
values.Proxy.Resources = &l5dcharts.Resources{
CPU: l5dcharts.Constraints{
Limit: "1.5",
Request: "0.15",
},
Memory: l5dcharts.Constraints{
Limit: "256",
Request: "120",
},
EphemeralStorage: l5dcharts.Constraints{
Limit: "50",
Request: "10",
},
}
values.Proxy.UID = 8500
values.Proxy.GID = 8500
values.ProxyInit.Image.Name = "cr.l5d.io/linkerd/proxy-init"
values.ProxyInit.Image.PullPolicy = pullPolicy
values.ProxyInit.Image.Version = version.ProxyInitVersion
values.ProxyInit.IgnoreInboundPorts = "4222,6222"
values.ProxyInit.IgnoreOutboundPorts = "8079,8080"
values.ProxyInit.SkipSubnets = "172.17.0.0/16"
values.Proxy.RequireIdentityOnInboundPorts = "8888,9999"
values.Proxy.OutboundConnectTimeout = "6000ms"
values.Proxy.InboundConnectTimeout = "600ms"
values.Proxy.OpaquePorts = "4320-4325,3306"
values.Proxy.Await = true
values.Proxy.AccessLog = "apache"
values.Proxy.ShutdownGracePeriod = "30000ms"
values.Proxy.OutboundDiscoveryCacheUnusedTimeout = "50s"
values.Proxy.InboundDiscoveryCacheUnusedTimeout = "900s"
values.Proxy.DisableOutboundProtocolDetectTimeout = true
values.Proxy.DisableInboundProtocolDetectTimeout = true
values.Proxy.NativeSidecar = true
return values
},
},
{id: "use defaults",
nsAnnotations: make(map[string]string),
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{},
Spec: corev1.PodSpec{},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
return values
},
},
{id: "use namespace overrides",
nsAnnotations: map[string]string{
k8s.ProxyImageAnnotation: "cr.l5d.io/linkerd/proxy",
k8s.ProxyImagePullPolicyAnnotation: pullPolicy,
k8s.ProxyInitImageAnnotation: "cr.l5d.io/linkerd/proxy-init",
k8s.ProxyControlPortAnnotation: "4000",
k8s.ProxyInboundPortAnnotation: "5000",
k8s.ProxyAdminPortAnnotation: "5001",
k8s.ProxyOutboundPortAnnotation: "5002",
k8s.ProxyPodInboundPortsAnnotation: "1234,5678",
k8s.ProxyIgnoreInboundPortsAnnotation: "4222,6222",
k8s.ProxyIgnoreOutboundPortsAnnotation: "8079,8080",
k8s.ProxyCPURequestAnnotation: "0.15",
k8s.ProxyMemoryRequestAnnotation: "120",
k8s.ProxyCPULimitAnnotation: "1.5",
k8s.ProxyMemoryLimitAnnotation: "256",
k8s.ProxyUIDAnnotation: "8500",
k8s.ProxyGIDAnnotation: "8500",
k8s.ProxyLogLevelAnnotation: "debug,linkerd=debug",
k8s.ProxyLogFormatAnnotation: "json",
k8s.ProxyEnableExternalProfilesAnnotation: "false",
k8s.ProxyVersionOverrideAnnotation: proxyVersionOverride,
k8s.ProxyWaitBeforeExitSecondsAnnotation: "123",
k8s.ProxyOutboundConnectTimeout: "6000ms",
k8s.ProxyInboundConnectTimeout: "600ms",
k8s.ProxyOpaquePortsAnnotation: "4320-4325,3306",
k8s.ProxyAwait: "enabled",
k8s.ProxyAccessLogAnnotation: "apache",
k8s.ProxyInjectAnnotation: "ingress",
k8s.ProxyOutboundDiscoveryCacheUnusedTimeout: "50s",
k8s.ProxyInboundDiscoveryCacheUnusedTimeout: "6000ms",
k8s.ProxyDisableOutboundProtocolDetectTimeout: "true",
k8s.ProxyDisableInboundProtocolDetectTimeout: "false",
k8s.ProxyEnableNativeSidecarAnnotation: "true",
},
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
values.Proxy.Runtime.Workers.Maximum = 2
values.Proxy.Image.Name = "cr.l5d.io/linkerd/proxy"
values.Proxy.Image.PullPolicy = pullPolicy
values.Proxy.Image.Version = proxyVersionOverride
values.Proxy.PodInboundPorts = "1234,5678"
values.Proxy.Ports.Control = 4000
values.Proxy.Ports.Inbound = 5000
values.Proxy.Ports.Admin = 5001
values.Proxy.Ports.Outbound = 5002
values.Proxy.WaitBeforeExitSeconds = 123
values.Proxy.LogLevel = "debug,linkerd=debug"
values.Proxy.LogFormat = "json"
values.Proxy.Resources = &l5dcharts.Resources{
CPU: l5dcharts.Constraints{
Limit: "1.5",
Request: "0.15",
},
Memory: l5dcharts.Constraints{
Limit: "256",
Request: "120",
},
}
values.Proxy.UID = 8500
values.Proxy.GID = 8500
values.ProxyInit.Image.Name = "cr.l5d.io/linkerd/proxy-init"
values.ProxyInit.Image.PullPolicy = pullPolicy
values.ProxyInit.Image.Version = version.ProxyInitVersion
values.ProxyInit.IgnoreInboundPorts = "4222,6222"
values.ProxyInit.IgnoreOutboundPorts = "8079,8080"
values.Proxy.OutboundConnectTimeout = "6000ms"
values.Proxy.InboundConnectTimeout = "600ms"
values.Proxy.OpaquePorts = "4320-4325,3306"
values.Proxy.Await = true
values.Proxy.AccessLog = "apache"
values.Proxy.IsIngress = true
values.Proxy.OutboundDiscoveryCacheUnusedTimeout = "50s"
values.Proxy.InboundDiscoveryCacheUnusedTimeout = "6s"
values.Proxy.DisableOutboundProtocolDetectTimeout = true
values.Proxy.DisableInboundProtocolDetectTimeout = false
values.Proxy.NativeSidecar = true
return values
},
},
{id: "use invalid duration for proxy timeouts",
nsAnnotations: map[string]string{
k8s.ProxyOutboundConnectTimeout: "6000",
k8s.ProxyInboundConnectTimeout: "600",
k8s.ProxyOutboundDiscoveryCacheUnusedTimeout: "50",
k8s.ProxyInboundDiscoveryCacheUnusedTimeout: "5000",
k8s.ProxyDisableOutboundProtocolDetectTimeout: "9000",
k8s.ProxyDisableInboundProtocolDetectTimeout: "9",
},
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{},
Spec: corev1.PodSpec{},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
return values
},
},
{id: "use valid duration for proxy timeouts",
nsAnnotations: map[string]string{
// Validate we're converting time values into ms for the proxy to parse correctly.
k8s.ProxyOutboundConnectTimeout: "6s5ms",
k8s.ProxyInboundConnectTimeout: "2s5ms",
k8s.ProxyOutboundDiscoveryCacheUnusedTimeout: "6s5000ms",
k8s.ProxyInboundDiscoveryCacheUnusedTimeout: "6s5000ms",
k8s.ProxyDisableOutboundProtocolDetectTimeout: "false",
k8s.ProxyDisableInboundProtocolDetectTimeout: "true",
},
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{},
Spec: corev1.PodSpec{},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
values.Proxy.OutboundConnectTimeout = "6005ms"
values.Proxy.InboundConnectTimeout = "2005ms"
values.Proxy.OutboundDiscoveryCacheUnusedTimeout = "11s"
values.Proxy.InboundDiscoveryCacheUnusedTimeout = "11s"
values.Proxy.DisableOutboundProtocolDetectTimeout = false
values.Proxy.DisableInboundProtocolDetectTimeout = true
return values
},
},
{id: "use named port for opaque ports",
nsAnnotations: make(map[string]string),
spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
k8s.ProxyOpaquePortsAnnotation: "mysql",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Ports: []corev1.ContainerPort{
{
Name: "mysql",
ContainerPort: 3306,
},
},
},
},
},
},
},
expected: func() *l5dcharts.Values {
values, _ := l5dcharts.NewValues()
values.Proxy.OpaquePorts = "3306"
return values
},
},
}
for _, tc := range testCases {
testCase := tc
t.Run(testCase.id, func(t *testing.T) {
data, err := yaml.Marshal(&appsv1.Deployment{Spec: testCase.spec})
if err != nil {
t.Fatal(err)
}
resourceConfig := NewResourceConfig(testConfig, OriginUnknown, "linkerd").
WithKind("Deployment").WithNsAnnotations(testCase.nsAnnotations)
if err := resourceConfig.parse(data); err != nil {
t.Fatal(err)
}
AppendNamespaceAnnotations(resourceConfig.GetOverrideAnnotations(), resourceConfig.GetNsAnnotations(), resourceConfig.GetWorkloadAnnotations())
actual, err := GetOverriddenValues(
resourceConfig.values,
resourceConfig.getAnnotationOverrides(),
util.GetNamedPorts(resourceConfig.pod.spec.Containers),
)
if err != nil {
t.Fatal(err)
}
expected := testCase.expected()
if diff := deep.Equal(actual, expected); diff != nil {
t.Errorf("%+v", diff)
}
})
}
}
func TestWholeCPUCores(t *testing.T) {
for _, c := range []struct {
v string
n int
}{
{v: "1", n: 1},
{v: "1m", n: 1},
{v: "1000m", n: 1},
{v: "1001m", n: 2},
} {
q, err := k8sResource.ParseQuantity(c.v)
if err != nil {
t.Fatal(err)
}
n, err := ToWholeCPUCores(q)
if err != nil {
t.Fatal(err)
}
if n != int64(c.n) {
t.Fatalf("Unexpected value: %v != %v", n, c.n)
}
}
}