mirror of https://github.com/linkerd/linkerd2.git
Check for Namespace level config override annotations (#3194)
* Check for Namespace level config override annotations * Add unit tests for namespace level config overrides * add integration test for namespace level config override * use different namespace for override tests * check resource requests for integration tests Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>
This commit is contained in:
parent
879650cef9
commit
242566ac7c
|
@ -537,7 +537,10 @@ func (conf *ResourceConfig) injectPodAnnotations(values *patch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *ResourceConfig) getOverride(annotation string) string {
|
func (conf *ResourceConfig) getOverride(annotation string) string {
|
||||||
return conf.pod.meta.Annotations[annotation]
|
if override := conf.pod.meta.Annotations[annotation]; override != "" {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
return conf.nsAnnotations[annotation]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *ResourceConfig) proxyImage() string {
|
func (conf *ResourceConfig) proxyImage() string {
|
||||||
|
|
|
@ -75,9 +75,10 @@ func TestConfigAccessors(t *testing.T) {
|
||||||
configs := &config.All{Global: globalConfig, Proxy: proxyConfig}
|
configs := &config.All{Global: globalConfig, Proxy: proxyConfig}
|
||||||
|
|
||||||
var testCases = []struct {
|
var testCases = []struct {
|
||||||
id string
|
id string
|
||||||
spec appsv1.DeploymentSpec
|
nsAnnotations map[string]string
|
||||||
expected expectedProxyConfigs
|
spec appsv1.DeploymentSpec
|
||||||
|
expected expectedProxyConfigs
|
||||||
}{
|
}{
|
||||||
{id: "use overrides",
|
{id: "use overrides",
|
||||||
spec: appsv1.DeploymentSpec{
|
spec: appsv1.DeploymentSpec{
|
||||||
|
@ -168,6 +169,58 @@ func TestConfigAccessors(t *testing.T) {
|
||||||
outboundSkipPorts: "9079",
|
outboundSkipPorts: "9079",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{id: "use namespace overrides",
|
||||||
|
nsAnnotations: map[string]string{
|
||||||
|
k8s.ProxyDisableIdentityAnnotation: "true",
|
||||||
|
k8s.ProxyImageAnnotation: "gcr.io/linkerd-io/proxy",
|
||||||
|
k8s.ProxyImagePullPolicyAnnotation: "Always",
|
||||||
|
k8s.ProxyInitImageAnnotation: "gcr.io/linkerd-io/proxy-init",
|
||||||
|
k8s.ProxyControlPortAnnotation: "4000",
|
||||||
|
k8s.ProxyInboundPortAnnotation: "5000",
|
||||||
|
k8s.ProxyAdminPortAnnotation: "5001",
|
||||||
|
k8s.ProxyOutboundPortAnnotation: "5002",
|
||||||
|
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.ProxyLogLevelAnnotation: "debug,linkerd2_proxy=debug",
|
||||||
|
k8s.ProxyEnableExternalProfilesAnnotation: "false",
|
||||||
|
k8s.ProxyVersionOverrideAnnotation: proxyVersionOverride},
|
||||||
|
spec: appsv1.DeploymentSpec{
|
||||||
|
Template: corev1.PodTemplateSpec{
|
||||||
|
Spec: corev1.PodSpec{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: expectedProxyConfigs{
|
||||||
|
image: "gcr.io/linkerd-io/proxy",
|
||||||
|
imagePullPolicy: "Always",
|
||||||
|
proxyVersion: proxyVersionOverride,
|
||||||
|
controlPort: int32(4000),
|
||||||
|
inboundPort: int32(5000),
|
||||||
|
adminPort: int32(5001),
|
||||||
|
outboundPort: int32(5002),
|
||||||
|
logLevel: "debug,linkerd2_proxy=debug",
|
||||||
|
resourceRequirements: &charts.Resources{
|
||||||
|
CPU: charts.Constraints{
|
||||||
|
Limit: "1500m",
|
||||||
|
Request: "150m",
|
||||||
|
},
|
||||||
|
Memory: charts.Constraints{
|
||||||
|
Limit: "256",
|
||||||
|
Request: "120",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
proxyUID: int64(8500),
|
||||||
|
initImage: "gcr.io/linkerd-io/proxy-init",
|
||||||
|
initImagePullPolicy: "Always",
|
||||||
|
initVersion: version.ProxyInitVersion,
|
||||||
|
inboundSkipPorts: "4222,6222",
|
||||||
|
outboundSkipPorts: "8079,8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -178,7 +231,7 @@ func TestConfigAccessors(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceConfig := NewResourceConfig(configs, OriginUnknown).WithKind("Deployment")
|
resourceConfig := NewResourceConfig(configs, OriginUnknown).WithKind("Deployment").WithNsAnnotations(testCase.nsAnnotations)
|
||||||
if err := resourceConfig.parse(data); err != nil {
|
if err := resourceConfig.parse(data); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
"github.com/linkerd/linkerd2/pkg/k8s"
|
||||||
"github.com/linkerd/linkerd2/pkg/version"
|
"github.com/linkerd/linkerd2/pkg/version"
|
||||||
|
@ -89,6 +92,72 @@ func TestInjectParams(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNamespaceOverrideAnnotations(t *testing.T) {
|
||||||
|
// Check for Namespace level override of proxy Configurations
|
||||||
|
injectYAML, err := testutil.ReadFile("testdata/inject_test.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read inject test file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
injectNS := "inject-namespace-override-test"
|
||||||
|
deployName := "inject-test-terminus"
|
||||||
|
nsProxyMemReq := "50Mi"
|
||||||
|
nsProxyCPUReq := "200m"
|
||||||
|
|
||||||
|
// Namespace level proxy configuration override
|
||||||
|
nsAnnotations := map[string]string{
|
||||||
|
k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled,
|
||||||
|
k8s.ProxyCPURequestAnnotation: nsProxyCPUReq,
|
||||||
|
k8s.ProxyMemoryRequestAnnotation: nsProxyMemReq,
|
||||||
|
}
|
||||||
|
|
||||||
|
ns := TestHelper.GetTestNamespace(injectNS)
|
||||||
|
err = TestHelper.CreateNamespaceIfNotExists(ns, nsAnnotations)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create %s namespace: %s", ns, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch injectYAML with unique name and pod annotations
|
||||||
|
// Pod Level proxy configuration override
|
||||||
|
podProxyCPUReq := "600m"
|
||||||
|
podAnnotations := map[string]string{
|
||||||
|
k8s.ProxyCPURequestAnnotation: podProxyCPUReq,
|
||||||
|
}
|
||||||
|
|
||||||
|
patchedYAML, err := patchDeploy(injectYAML, deployName, podAnnotations)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to patch inject test YAML in namespace %s for deploy/%s: %s", ns, deployName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
o, err := TestHelper.Kubectl(patchedYAML, "--namespace", ns, "create", "-f", "-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create deploy/%s in namespace %s for %s: %s", deployName, ns, err, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
o, err = TestHelper.Kubectl("", "--namespace", ns, "wait", "--for=condition=available", "--timeout=30s", "deploy/"+deployName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to wait for condition=available for deploy/%s in namespace %s: %s: %s", deployName, ns, err, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
pods, err := TestHelper.GetPodsForDeployment(ns, deployName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get pods for namespace %s: %s", ns, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containers := pods[0].Spec.Containers
|
||||||
|
proxyContainer := getProxyContainer(containers)
|
||||||
|
|
||||||
|
// Match the pod configuration with the namespace level overrides
|
||||||
|
if proxyContainer.Resources.Requests["memory"] != resource.MustParse(nsProxyMemReq) {
|
||||||
|
t.Fatalf("proxy memory resource request falied to match with namespace level override")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match with proxy level override
|
||||||
|
if proxyContainer.Resources.Requests["cpu"] != resource.MustParse(podProxyCPUReq) {
|
||||||
|
t.Fatalf("proxy cpu resource request falied to match with pod level override")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAnnotationPermutations(t *testing.T) {
|
func TestAnnotationPermutations(t *testing.T) {
|
||||||
injectYAML, err := testutil.ReadFile("testdata/inject_test.yaml")
|
injectYAML, err := testutil.ReadFile("testdata/inject_test.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -287,3 +356,15 @@ func validateInject(actual, fixtureFile string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get Proxy Container from Containers
|
||||||
|
func getProxyContainer(containers []v1.Container) *v1.Container {
|
||||||
|
for _, c := range containers {
|
||||||
|
container := c
|
||||||
|
if container.Name == k8s.ProxyContainerName {
|
||||||
|
return &container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue