Hold bad AppArmor pods in pending rather than rejecting

This commit is contained in:
Tim St. Clair
2016-11-02 11:05:16 -07:00
parent df8db653da
commit ec9111d942
7 changed files with 126 additions and 31 deletions

View File

@@ -26,8 +26,11 @@ import (
"strconv"
"strings"
"k8s.io/client-go/pkg/api/errors"
"k8s.io/client-go/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/security/apparmor"
"k8s.io/kubernetes/pkg/watch"
"k8s.io/kubernetes/test/e2e/framework"
"github.com/davecgh/go-spew/spew"
@@ -46,12 +49,11 @@ var _ = framework.KubeDescribe("AppArmor [Feature:AppArmor]", func() {
f := framework.NewDefaultFramework("apparmor-test")
It("should reject an unloaded profile", func() {
status := runAppArmorTest(f, apparmor.ProfileNamePrefix+"non-existant-profile")
Expect(status.Phase).To(Equal(api.PodFailed), "PodStatus: %+v", status)
Expect(status.Reason).To(Equal("AppArmor"), "PodStatus: %+v", status)
status := runAppArmorTest(f, false, apparmor.ProfileNamePrefix+"non-existant-profile")
expectSoftRejection(status)
})
It("should enforce a profile blocking writes", func() {
status := runAppArmorTest(f, apparmor.ProfileNamePrefix+apparmorProfilePrefix+"deny-write")
status := runAppArmorTest(f, true, apparmor.ProfileNamePrefix+apparmorProfilePrefix+"deny-write")
if len(status.ContainerStatuses) == 0 {
framework.Failf("Unexpected pod status: %s", spew.Sdump(status))
return
@@ -61,7 +63,7 @@ var _ = framework.KubeDescribe("AppArmor [Feature:AppArmor]", func() {
})
It("should enforce a permissive profile", func() {
status := runAppArmorTest(f, apparmor.ProfileNamePrefix+apparmorProfilePrefix+"audit-write")
status := runAppArmorTest(f, true, apparmor.ProfileNamePrefix+apparmorProfilePrefix+"audit-write")
if len(status.ContainerStatuses) == 0 {
framework.Failf("Unexpected pod status: %s", spew.Sdump(status))
return
@@ -75,9 +77,8 @@ var _ = framework.KubeDescribe("AppArmor [Feature:AppArmor]", func() {
f := framework.NewDefaultFramework("apparmor-test")
It("should reject a pod with an AppArmor profile", func() {
status := runAppArmorTest(f, apparmor.ProfileRuntimeDefault)
Expect(status.Phase).To(Equal(api.PodFailed), "PodStatus: %+v", status)
Expect(status.Reason).To(Equal("AppArmor"), "PodStatus: %+v", status)
status := runAppArmorTest(f, false, apparmor.ProfileRuntimeDefault)
expectSoftRejection(status)
})
})
}
@@ -136,11 +137,31 @@ func loadTestProfiles() error {
return nil
}
func runAppArmorTest(f *framework.Framework, profile string) api.PodStatus {
func runAppArmorTest(f *framework.Framework, shouldRun bool, profile string) api.PodStatus {
pod := createPodWithAppArmor(f, profile)
// The pod needs to start before it stops, so wait for the longer start timeout.
framework.ExpectNoError(framework.WaitTimeoutForPodNoLongerRunningInNamespace(
f.ClientSet, pod.Name, f.Namespace.Name, "", framework.PodStartTimeout))
if shouldRun {
// The pod needs to start before it stops, so wait for the longer start timeout.
framework.ExpectNoError(framework.WaitTimeoutForPodNoLongerRunningInNamespace(
f.ClientSet, pod.Name, f.Namespace.Name, "", framework.PodStartTimeout))
} else {
// Pod should remain in the pending state. Wait for the Reason to be set to "AppArmor".
w, err := f.PodClient().Watch(api.SingleObject(api.ObjectMeta{Name: pod.Name}))
framework.ExpectNoError(err)
_, err = watch.Until(framework.PodStartTimeout, w, func(e watch.Event) (bool, error) {
switch e.Type {
case watch.Deleted:
return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, pod.Name)
}
switch t := e.Object.(type) {
case *api.Pod:
if t.Status.Reason == "AppArmor" {
return true, nil
}
}
return false, nil
})
framework.ExpectNoError(err)
}
p, err := f.PodClient().Get(pod.Name)
framework.ExpectNoError(err)
return p.Status
@@ -166,6 +187,14 @@ func createPodWithAppArmor(f *framework.Framework, profile string) *api.Pod {
return f.PodClient().Create(pod)
}
func expectSoftRejection(status api.PodStatus) {
args := []interface{}{"PodStatus: %+v", status}
Expect(status.Phase).To(Equal(api.PodPending), args...)
Expect(status.Reason).To(Equal("AppArmor"), args...)
Expect(status.Message).To(ContainSubstring("AppArmor"), args...)
Expect(status.ContainerStatuses[0].State.Waiting.Reason).To(Equal("Blocked"), args...)
}
func isAppArmorEnabled() bool {
// TODO(timstclair): Pass this through the image setup rather than hardcoding.
if strings.Contains(framework.TestContext.NodeName, "-gci-dev-") {