Commit 99b2ee16 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #52106 from tallclair/aa-e2e

Automatic merge from submit-queue (batch tested with PRs 50289, 52106) Fix AppArmor test at scale **What this PR does / why we need it**: The AppArmor test only runs on a single node, but previously was loading the necessary profiles to every node. This caused unnecessary churn in very large clusters, so this PR updates the test to only load the profiles to a single node, and ensure the test pod is run on that node (using pod affinity). **Which issue this PR fixes**: fixes #51791 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```
parents ae8780f5 2604f676
...@@ -50,7 +50,6 @@ go_library( ...@@ -50,7 +50,6 @@ go_library(
"//vendor/golang.org/x/net/websocket:go_default_library", "//vendor/golang.org/x/net/websocket:go_default_library",
"//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
......
...@@ -20,16 +20,21 @@ import ( ...@@ -20,16 +20,21 @@ import (
"fmt" "fmt"
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/pkg/security/apparmor" "k8s.io/kubernetes/pkg/security/apparmor"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
. "github.com/onsi/gomega"
) )
const ( const (
appArmorProfilePrefix = "e2e-apparmor-test-" appArmorProfilePrefix = "e2e-apparmor-test-"
appArmorAllowedPath = "/expect_allowed_write" appArmorAllowedPath = "/expect_allowed_write"
appArmorDeniedPath = "/expect_permission_denied" appArmorDeniedPath = "/expect_permission_denied"
loaderLabelKey = "name"
loaderLabelValue = "e2e-apparmor-loader"
) )
// AppArmorDistros are distros with AppArmor support // AppArmorDistros are distros with AppArmor support
...@@ -40,10 +45,8 @@ func SkipIfAppArmorNotSupported() { ...@@ -40,10 +45,8 @@ func SkipIfAppArmorNotSupported() {
} }
func LoadAppArmorProfiles(f *framework.Framework) { func LoadAppArmorProfiles(f *framework.Framework) {
_, err := createAppArmorProfileCM(f) createAppArmorProfileCM(f)
framework.ExpectNoError(err) createAppArmorProfileLoader(f)
_, err = createAppArmorProfileLoader(f)
framework.ExpectNoError(err)
} }
// CreateAppArmorTestPod creates a pod that tests apparmor profile enforcement. The pod exits with // CreateAppArmorTestPod creates a pod that tests apparmor profile enforcement. The pod exits with
...@@ -71,6 +74,18 @@ sleep 1 ...@@ -71,6 +74,18 @@ sleep 1
done`, testCmd) done`, testCmd)
} }
loaderAffinity := &api.Affinity{
PodAffinity: &api.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{{
Namespaces: []string{f.Namespace.Name},
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{loaderLabelKey: loaderLabelValue},
},
TopologyKey: "kubernetes.io/hostname",
}},
},
}
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-apparmor-", GenerateName: "test-apparmor-",
...@@ -82,6 +97,7 @@ done`, testCmd) ...@@ -82,6 +97,7 @@ done`, testCmd)
}, },
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Affinity: loaderAffinity,
Containers: []api.Container{{ Containers: []api.Container{{
Name: "test", Name: "test",
Image: busyboxImage, Image: busyboxImage,
...@@ -95,15 +111,22 @@ done`, testCmd) ...@@ -95,15 +111,22 @@ done`, testCmd)
pod = f.PodClient().Create(pod) pod = f.PodClient().Create(pod)
framework.ExpectNoError(framework.WaitForPodSuccessInNamespace( framework.ExpectNoError(framework.WaitForPodSuccessInNamespace(
f.ClientSet, pod.Name, f.Namespace.Name)) f.ClientSet, pod.Name, f.Namespace.Name))
var err error
pod, err = f.PodClient().Get(pod.Name, metav1.GetOptions{})
framework.ExpectNoError(err)
} else { } else {
pod = f.PodClient().CreateSync(pod) pod = f.PodClient().CreateSync(pod)
framework.ExpectNoError(f.WaitForPodReady(pod.Name)) framework.ExpectNoError(f.WaitForPodReady(pod.Name))
} }
// Verify Pod affinity colocated the Pods.
loader := getRunningLoaderPod(f)
Expect(pod.Spec.NodeName).To(Equal(loader.Spec.NodeName))
return pod return pod
} }
func createAppArmorProfileCM(f *framework.Framework) (*api.ConfigMap, error) { func createAppArmorProfileCM(f *framework.Framework) {
profileName := appArmorProfilePrefix + f.Namespace.Name profileName := appArmorProfilePrefix + f.Namespace.Name
profile := fmt.Sprintf(`#include <tunables/global> profile := fmt.Sprintf(`#include <tunables/global>
profile %s flags=(attach_disconnected) { profile %s flags=(attach_disconnected) {
...@@ -125,21 +148,23 @@ profile %s flags=(attach_disconnected) { ...@@ -125,21 +148,23 @@ profile %s flags=(attach_disconnected) {
profileName: profile, profileName: profile,
}, },
} }
return f.ClientSet.Core().ConfigMaps(f.Namespace.Name).Create(cm) _, err := f.ClientSet.Core().ConfigMaps(f.Namespace.Name).Create(cm)
framework.ExpectNoError(err, "Failed to create apparmor-profiles ConfigMap")
} }
func createAppArmorProfileLoader(f *framework.Framework) (*extensions.DaemonSet, error) { func createAppArmorProfileLoader(f *framework.Framework) {
True := true True := true
// Copied from https://github.com/kubernetes/contrib/blob/master/apparmor/loader/example-configmap.yaml One := int32(1)
loader := &extensions.DaemonSet{ loader := &api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "apparmor-loader", Name: "apparmor-loader",
Namespace: f.Namespace.Name, Namespace: f.Namespace.Name,
}, },
Spec: extensions.DaemonSetSpec{ Spec: api.ReplicationControllerSpec{
Template: api.PodTemplateSpec{ Replicas: &One,
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"name": "apparmor-loader"}, Labels: map[string]string{loaderLabelKey: loaderLabelValue},
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{{ Containers: []api.Container{{
...@@ -191,5 +216,18 @@ func createAppArmorProfileLoader(f *framework.Framework) (*extensions.DaemonSet, ...@@ -191,5 +216,18 @@ func createAppArmorProfileLoader(f *framework.Framework) (*extensions.DaemonSet,
}, },
}, },
} }
return f.ClientSet.Extensions().DaemonSets(f.Namespace.Name).Create(loader) _, err := f.ClientSet.Core().ReplicationControllers(f.Namespace.Name).Create(loader)
framework.ExpectNoError(err, "Failed to create apparmor-loader ReplicationController")
// Wait for loader to be ready.
getRunningLoaderPod(f)
}
func getRunningLoaderPod(f *framework.Framework) *api.Pod {
label := labels.SelectorFromSet(labels.Set(map[string]string{loaderLabelKey: loaderLabelValue}))
pods, err := framework.WaitForPodsWithLabelScheduled(f.ClientSet, f.Namespace.Name, label)
framework.ExpectNoError(err, "Failed to schedule apparmor-loader Pod")
pod := &pods.Items[0]
framework.ExpectNoError(framework.WaitForPodRunningInNamespace(f.ClientSet, pod), "Failed to run apparmor-loader Pod")
return pod
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment