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
```
This commit is contained in:
Kubernetes Submit Queue 2017-09-12 03:44:18 -07:00 committed by GitHub
commit 99b2ee1697
2 changed files with 52 additions and 15 deletions

View File

@ -50,7 +50,6 @@ go_library(
"//vendor/golang.org/x/net/websocket: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/extensions/v1beta1: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/fields:go_default_library",

View File

@ -20,16 +20,21 @@ import (
"fmt"
api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/pkg/security/apparmor"
"k8s.io/kubernetes/test/e2e/framework"
. "github.com/onsi/gomega"
)
const (
appArmorProfilePrefix = "e2e-apparmor-test-"
appArmorAllowedPath = "/expect_allowed_write"
appArmorDeniedPath = "/expect_permission_denied"
loaderLabelKey = "name"
loaderLabelValue = "e2e-apparmor-loader"
)
// AppArmorDistros are distros with AppArmor support
@ -40,10 +45,8 @@ func SkipIfAppArmorNotSupported() {
}
func LoadAppArmorProfiles(f *framework.Framework) {
_, err := createAppArmorProfileCM(f)
framework.ExpectNoError(err)
_, err = createAppArmorProfileLoader(f)
framework.ExpectNoError(err)
createAppArmorProfileCM(f)
createAppArmorProfileLoader(f)
}
// CreateAppArmorTestPod creates a pod that tests apparmor profile enforcement. The pod exits with
@ -71,6 +74,18 @@ sleep 1
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{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-apparmor-",
@ -82,6 +97,7 @@ done`, testCmd)
},
},
Spec: api.PodSpec{
Affinity: loaderAffinity,
Containers: []api.Container{{
Name: "test",
Image: busyboxImage,
@ -95,15 +111,22 @@ done`, testCmd)
pod = f.PodClient().Create(pod)
framework.ExpectNoError(framework.WaitForPodSuccessInNamespace(
f.ClientSet, pod.Name, f.Namespace.Name))
var err error
pod, err = f.PodClient().Get(pod.Name, metav1.GetOptions{})
framework.ExpectNoError(err)
} else {
pod = f.PodClient().CreateSync(pod)
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
}
func createAppArmorProfileCM(f *framework.Framework) (*api.ConfigMap, error) {
func createAppArmorProfileCM(f *framework.Framework) {
profileName := appArmorProfilePrefix + f.Namespace.Name
profile := fmt.Sprintf(`#include <tunables/global>
profile %s flags=(attach_disconnected) {
@ -125,21 +148,23 @@ profile %s flags=(attach_disconnected) {
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
// Copied from https://github.com/kubernetes/contrib/blob/master/apparmor/loader/example-configmap.yaml
loader := &extensions.DaemonSet{
One := int32(1)
loader := &api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "apparmor-loader",
Namespace: f.Namespace.Name,
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{
Spec: api.ReplicationControllerSpec{
Replicas: &One,
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"name": "apparmor-loader"},
Labels: map[string]string{loaderLabelKey: loaderLabelValue},
},
Spec: api.PodSpec{
Containers: []api.Container{{
@ -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
}