sigs.k8s.io/kubebuilder/v3@v3.14.0/test/e2e/deployimage/plugin_cluster_test.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package deployimage 18 19 import ( 20 "errors" 21 "fmt" 22 "os/exec" 23 "path/filepath" 24 "strings" 25 "time" 26 27 "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util" 28 29 //nolint:golint 30 //nolint:revive 31 . "github.com/onsi/ginkgo/v2" 32 33 //nolint:golint 34 //nolint:revive 35 . "github.com/onsi/gomega" 36 37 "sigs.k8s.io/kubebuilder/v3/test/e2e/utils" 38 ) 39 40 var _ = Describe("kubebuilder", func() { 41 Context("deploy image plugin", func() { 42 var kbc *utils.TestContext 43 44 BeforeEach(func() { 45 var err error 46 kbc, err = utils.NewTestContext(util.KubebuilderBinName, "GO111MODULE=on") 47 Expect(err).NotTo(HaveOccurred()) 48 Expect(kbc.Prepare()).To(Succeed()) 49 50 By("installing prometheus operator") 51 Expect(kbc.InstallPrometheusOperManager()).To(Succeed()) 52 53 By("creating manager namespace") 54 err = kbc.CreateManagerNamespace() 55 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 56 57 By("labeling all namespaces to warn about restricted") 58 err = kbc.LabelAllNamespacesToWarnAboutRestricted() 59 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 60 61 By("enforce that namespace where the sample will be applied can only run restricted containers") 62 _, err = kbc.Kubectl.Command("label", "--overwrite", "ns", kbc.Kubectl.Namespace, 63 "pod-security.kubernetes.io/audit=restricted", 64 "pod-security.kubernetes.io/enforce-version=v1.24", 65 "pod-security.kubernetes.io/enforce=restricted") 66 Expect(err).To(Not(HaveOccurred())) 67 }) 68 69 AfterEach(func() { 70 By("clean up API objects created during the test") 71 kbc.CleanupManifests(filepath.Join("config", "default")) 72 73 By("uninstalling the Prometheus manager bundle") 74 kbc.UninstallPrometheusOperManager() 75 76 By("removing controller image and working dir") 77 kbc.Destroy() 78 }) 79 80 It("should generate a runnable project with deploy-image/v1-alpha options ", func() { 81 var err error 82 83 By("initializing a project with go/v3") 84 err = kbc.Init( 85 "--plugins", "go/v4", 86 "--project-version", "3", 87 "--domain", kbc.Domain, 88 ) 89 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 90 91 By("creating API definition with deploy-image/v1-alpha plugin") 92 err = kbc.CreateAPI( 93 "--group", kbc.Group, 94 "--version", kbc.Version, 95 "--kind", kbc.Kind, 96 "--plugins", "deploy-image/v1-alpha", 97 "--image", "memcached:1.4.36-alpine", 98 "--image-container-port", "11211", 99 "--image-container-command", "memcached,-m=64,-o,modern,-v", 100 "--run-as-user", "1001", 101 "--make=false", 102 "--manifests=false", 103 ) 104 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 105 106 By("uncomment kustomization.yaml to enable prometheus") 107 ExpectWithOffset(1, util.UncommentCode( 108 filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"), 109 "#- ../prometheus", "#")).To(Succeed()) 110 111 By("uncomment kustomize files to ensure that pods are restricted") 112 uncommentPodStandards(kbc) 113 114 Run(kbc) 115 }) 116 117 It("should generate a runnable project with deploy-image/v1-alpha without options ", func() { 118 var err error 119 120 By("initializing a project with go/v4") 121 err = kbc.Init( 122 "--plugins", "go/v4", 123 "--project-version", "3", 124 "--domain", kbc.Domain, 125 ) 126 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 127 128 By("creating API definition with deploy-image/v1-alpha plugin") 129 err = kbc.CreateAPI( 130 "--group", kbc.Group, 131 "--version", kbc.Version, 132 "--kind", kbc.Kind, 133 "--plugins", "deploy-image/v1-alpha", 134 "--image", "busybox:1.28", 135 "--make=false", 136 "--manifests=false", 137 ) 138 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 139 140 By("uncomment kustomization.yaml to enable prometheus") 141 ExpectWithOffset(1, util.UncommentCode( 142 filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"), 143 "#- ../prometheus", "#")).To(Succeed()) 144 145 By("uncomment kustomize files to ensure that pods are restricted") 146 uncommentPodStandards(kbc) 147 148 Run(kbc) 149 }) 150 }) 151 }) 152 153 // Run runs a set of e2e tests for a scaffolded project defined by a TestContext. 154 func Run(kbc *utils.TestContext) { 155 var controllerPodName string 156 var err error 157 158 By("updating the go.mod") 159 err = kbc.Tidy() 160 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 161 162 By("run make manifests") 163 err = kbc.Make("manifests") 164 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 165 166 By("run make generate") 167 err = kbc.Make("generate") 168 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 169 170 By("run make all") 171 err = kbc.Make("all") 172 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 173 174 By("run make install") 175 err = kbc.Make("install") 176 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 177 178 By("building the controller image") 179 err = kbc.Make("docker-build", "IMG="+kbc.ImageName) 180 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 181 182 By("loading the controller docker image into the kind cluster") 183 err = kbc.LoadImageToKindCluster() 184 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 185 186 By("deploying the controller-manager") 187 cmd := exec.Command("make", "deploy", "IMG="+kbc.ImageName) 188 outputMake, err := kbc.Run(cmd) 189 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 190 191 By("validating that manager Pod/container(s) are restricted") 192 ExpectWithOffset(1, outputMake).NotTo(ContainSubstring("Warning: would violate PodSecurity")) 193 194 By("validating that the controller-manager pod is running as expected") 195 verifyControllerUp := func() error { 196 // Get pod name 197 podOutput, err := kbc.Kubectl.Get( 198 true, 199 "pods", "-l", "control-plane=controller-manager", 200 "-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}"+ 201 "{{ \"\\n\" }}{{ end }}{{ end }}") 202 ExpectWithOffset(2, err).NotTo(HaveOccurred()) 203 podNames := util.GetNonEmptyLines(podOutput) 204 if len(podNames) != 1 { 205 return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames)) 206 } 207 controllerPodName = podNames[0] 208 ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager")) 209 210 // Validate pod status 211 status, err := kbc.Kubectl.Get( 212 true, 213 "pods", controllerPodName, "-o", "jsonpath={.status.phase}") 214 ExpectWithOffset(2, err).NotTo(HaveOccurred()) 215 if status != "Running" { 216 return fmt.Errorf("controller pod in %s status", status) 217 } 218 return nil 219 } 220 defer func() { 221 out, err := kbc.Kubectl.CommandInNamespace("describe", "all") 222 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 223 fmt.Fprintln(GinkgoWriter, out) 224 }() 225 EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed()) 226 By("creating an instance of the CR") 227 sampleFile := filepath.Join("config", "samples", 228 fmt.Sprintf("%s_%s_%s.yaml", kbc.Group, kbc.Version, strings.ToLower(kbc.Kind))) 229 230 sampleFilePath, err := filepath.Abs(filepath.Join(fmt.Sprintf("e2e-%s", kbc.TestSuffix), sampleFile)) 231 Expect(err).To(Not(HaveOccurred())) 232 233 EventuallyWithOffset(1, func() error { 234 _, err = kbc.Kubectl.Apply(true, "-f", sampleFilePath) 235 return err 236 }, time.Minute, time.Second).Should(Succeed()) 237 238 By("validating that pod(s) status.phase=Running") 239 getMemcachedPodStatus := func() error { 240 status, err := kbc.Kubectl.Get(true, "pods", "-l", 241 fmt.Sprintf("app.kubernetes.io/name=%s", kbc.Kind), 242 "-o", "jsonpath={.items[*].status}", 243 ) 244 ExpectWithOffset(2, err).NotTo(HaveOccurred()) 245 if !strings.Contains(status, "\"phase\":\"Running\"") { 246 return err 247 } 248 return nil 249 } 250 EventuallyWithOffset(1, getMemcachedPodStatus, time.Minute, time.Second).Should(Succeed()) 251 252 By("validating that the status of the custom resource created is updated or not") 253 var status string 254 getStatus := func() error { 255 status, err = kbc.Kubectl.Get(true, strings.ToLower(kbc.Kind), 256 strings.ToLower(kbc.Kind)+"-sample", 257 "-o", "jsonpath={.status.conditions}") 258 ExpectWithOffset(2, err).NotTo(HaveOccurred()) 259 if !strings.Contains(status, "Available") { 260 return errors.New(`status condition with type "Available" should be set`) 261 } 262 return nil 263 } 264 Eventually(getStatus, time.Minute, time.Second).Should(Succeed()) 265 266 // Testing the finalizer 267 EventuallyWithOffset(1, func() error { 268 _, err = kbc.Kubectl.Delete(true, "-f", sampleFilePath) 269 return err 270 }, time.Minute, time.Second).Should(Succeed()) 271 272 EventuallyWithOffset(1, func() error { 273 events, err := kbc.Kubectl.Get(true, "events", "--field-selector=type=Warning", 274 "-o", "jsonpath={.items[*].message}", 275 ) 276 ExpectWithOffset(2, err).NotTo(HaveOccurred()) 277 if !strings.Contains(events, "is being deleted from the namespace") { 278 return err 279 } 280 return nil 281 }, time.Minute, time.Second).Should(Succeed()) 282 } 283 284 func uncommentPodStandards(kbc *utils.TestContext) { 285 configManager := filepath.Join(kbc.Dir, "config", "manager", "manager.yaml") 286 287 //nolint:lll 288 if err := util.ReplaceInFile(configManager, `# TODO(user): For common cases that do not require escalating privileges 289 # it is recommended to ensure that all your Pods/Containers are restrictive. 290 # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted 291 # Please uncomment the following code if your project does NOT have to work on old Kubernetes 292 # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). 293 # seccompProfile: 294 # type: RuntimeDefault`, `seccompProfile: 295 type: RuntimeDefault`); err == nil { 296 ExpectWithOffset(1, err).NotTo(HaveOccurred()) 297 } 298 }