Hold bad AppArmor pods in pending rather than rejecting
This commit is contained in:
@@ -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-") {
|
||||
|
Reference in New Issue
Block a user