From 119f5113e06335b4819dc6b3a5827515f5184070 Mon Sep 17 00:00:00 2001 From: Tadayoshi Sato Date: Thu, 17 Dec 2020 18:05:55 +0900 Subject: [PATCH] chore(e2e): add test for Affinity trait #1547 --- e2e/common/affinity_test.go | 150 ++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 e2e/common/affinity_test.go diff --git a/e2e/common/affinity_test.go b/e2e/common/affinity_test.go new file mode 100644 index 0000000000..2711551931 --- /dev/null +++ b/e2e/common/affinity_test.go @@ -0,0 +1,150 @@ +// +build integration + +// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration" + +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "fmt" + "testing" + + . "github.com/apache/camel-k/e2e/support" + camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1" + + . "github.com/onsi/gomega" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestAffinityTrait(t *testing.T) { + WithNewTestNamespace(t, func(ns string) { + Expect(Kamel("install", "-n", ns).Execute()).Should(BeNil()) + + var hostname string + if node, err := selectSchedulableNode(); err == nil { + hostname = node.Labels["kubernetes.io/hostname"] + } else { + // if 'get nodes' is not allowed, just skip tests for node affinity + hostname = "" + } + + if hostname != "" { + t.Run("Run Java with node affinity", func(t *testing.T) { + Expect(Kamel("run", "-n", ns, "files/Java.java", + "-t", "affinity.enabled=true", + "-t", fmt.Sprintf("affinity.node-affinity-labels=kubernetes.io/hostname in(%s)", hostname)).Execute()).Should(BeNil()) + Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutLong).Should(Equal(v1.PodRunning)) + Eventually(IntegrationCondition(ns, "java", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue)) + Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) + + pod := IntegrationPod(ns, "java")() + Expect(pod.Spec.Affinity).ShouldNot(BeNil()) + Expect(pod.Spec.Affinity.NodeAffinity).Should(Equal(&v1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: nodeSelector("kubernetes.io/hostname", v1.NodeSelectorOpIn, hostname), + })) + Expect(pod.Spec.NodeName).Should(Equal(hostname)) + + Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil()) + }) + } + + t.Run("Run Java with pod affinity", func(t *testing.T) { + Expect(Kamel("run", "-n", ns, "files/Java.java", + "-t", "affinity.enabled=true", + "-t", "affinity.pod-affinity-labels=camel.apache.org/integration").Execute()).Should(BeNil()) + Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutLong).Should(Equal(v1.PodRunning)) + Eventually(IntegrationCondition(ns, "java", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue)) + Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) + + pod := IntegrationPod(ns, "java")() + Expect(pod.Spec.Affinity).ShouldNot(BeNil()) + Expect(pod.Spec.Affinity.PodAffinity).Should(Equal(&v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + podAffinityTerm("camel.apache.org/integration", metav1.LabelSelectorOpExists, "kubernetes.io/hostname"), + }, + })) + + Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil()) + }) + + t.Run("Run Java with pod anti affinity", func(t *testing.T) { + Expect(Kamel("run", "-n", ns, "files/Java.java", + "-t", "affinity.enabled=true", + "-t", "affinity.pod-anti-affinity-labels=camel.apache.org/integration").Execute()).Should(BeNil()) + Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutLong).Should(Equal(v1.PodRunning)) + Eventually(IntegrationCondition(ns, "java", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue)) + Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) + + pod := IntegrationPod(ns, "java")() + Expect(pod.Spec.Affinity).ShouldNot(BeNil()) + Expect(pod.Spec.Affinity.PodAntiAffinity).Should(Equal(&v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + podAffinityTerm("camel.apache.org/integration", metav1.LabelSelectorOpExists, "kubernetes.io/hostname"), + }, + })) + + Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil()) + }) + }) +} + +func selectSchedulableNode() (*v1.Node, error) { + nodes, err := TestClient.CoreV1().Nodes().List(TestContext, metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, node := range nodes.Items { + if node.Spec.Taints == nil { + return &node, nil + } + } + return nil, fmt.Errorf("No node available") +} + +func nodeSelector(key string, operator v1.NodeSelectorOperator, value string) *v1.NodeSelector { + return &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: key, + Operator: operator, + Values: []string{value}, + }, + }, + }, + }, + } +} + +func podAffinityTerm(key string, operator metav1.LabelSelectorOperator, topologyKey string) v1.PodAffinityTerm { + return v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: key, + Operator: operator, + }, + }, + }, + TopologyKey: topologyKey, + } +}