1
16
17 package node
18
19 import (
20 "context"
21
22 v1 "k8s.io/api/core/v1"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/kubernetes/test/e2e/framework"
25 e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
26 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
27 e2esecurity "k8s.io/kubernetes/test/e2e/framework/security"
28 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
29 "k8s.io/kubernetes/test/e2e/upgrades"
30
31 "github.com/onsi/ginkgo/v2"
32 "github.com/onsi/gomega"
33 "github.com/onsi/gomega/gstruct"
34 )
35
36
37 type AppArmorUpgradeTest struct {
38 pod *v1.Pod
39 }
40
41
42 func (AppArmorUpgradeTest) Name() string { return "apparmor-upgrade" }
43
44
45 func (AppArmorUpgradeTest) Skip(upgCtx upgrades.UpgradeContext) bool {
46 supportedImages := make(map[string]bool)
47 for _, d := range e2eskipper.AppArmorDistros {
48 supportedImages[d] = true
49 }
50
51 for _, vCtx := range upgCtx.Versions {
52 if !supportedImages[vCtx.NodeImage] {
53 return true
54 }
55 }
56 return false
57 }
58
59
60 func (t *AppArmorUpgradeTest) Setup(ctx context.Context, f *framework.Framework) {
61 ginkgo.By("Loading AppArmor profiles to nodes")
62 e2esecurity.LoadAppArmorProfiles(ctx, f.Namespace.Name, f.ClientSet)
63
64
65 ginkgo.By("Creating a long-running AppArmor enabled pod.")
66 pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, false)
67 t.pod = e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), false)
68
69
70 t.verifyNodesAppArmorEnabled(ctx, f)
71 t.verifyNewPodSucceeds(ctx, f)
72 }
73
74
75
76 func (t *AppArmorUpgradeTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
77 <-done
78 if upgrade == upgrades.MasterUpgrade {
79 t.verifyPodStillUp(ctx, f)
80 }
81 t.verifyNodesAppArmorEnabled(ctx, f)
82 t.verifyNewPodSucceeds(ctx, f)
83 }
84
85
86 func (t *AppArmorUpgradeTest) Teardown(ctx context.Context, f *framework.Framework) {
87
88 ginkgo.By("Logging container failures")
89 e2ekubectl.LogFailedContainers(ctx, f.ClientSet, f.Namespace.Name, framework.Logf)
90 }
91
92 func (t *AppArmorUpgradeTest) verifyPodStillUp(ctx context.Context, f *framework.Framework) {
93 ginkgo.By("Verifying an AppArmor profile is continuously enforced for a pod")
94 pod, err := e2epod.NewPodClient(f).Get(ctx, t.pod.Name, metav1.GetOptions{})
95 framework.ExpectNoError(err, "Should be able to get pod")
96 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodRunning), "Pod should stay running")
97 gomega.Expect(pod.Status.ContainerStatuses[0].State.Running).NotTo(gomega.BeNil(), "Container should be running")
98 gomega.Expect(pod.Status.ContainerStatuses[0].RestartCount).To(gomega.BeZero(), "Container should not need to be restarted")
99 }
100
101 func (t *AppArmorUpgradeTest) verifyNewPodSucceeds(ctx context.Context, f *framework.Framework) {
102 ginkgo.By("Verifying an AppArmor profile is enforced for a new pod")
103 pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, true)
104 t.pod = e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true)
105 }
106
107 func (t *AppArmorUpgradeTest) verifyNodesAppArmorEnabled(ctx context.Context, f *framework.Framework) {
108 ginkgo.By("Verifying nodes are AppArmor enabled")
109 nodes, err := f.ClientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
110 framework.ExpectNoError(err, "Failed to list nodes")
111 for _, node := range nodes.Items {
112 gomega.Expect(node.Status.Conditions).To(gstruct.MatchElements(conditionType, gstruct.IgnoreExtras, gstruct.Elements{
113 "Ready": gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
114 "Message": gomega.ContainSubstring("AppArmor enabled"),
115 }),
116 }))
117 }
118 }
119
120 func conditionType(condition interface{}) string {
121 return string(condition.(v1.NodeCondition).Type)
122 }
123
View as plain text