github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/e2e/toolbox_test.go (about) 1 package integration 2 3 /* 4 toolbox_test.go is under the care of the Toolbox Team. 5 6 The tests are trying to stress parts of Podman that Toolbox[0] needs for 7 its functionality. 8 9 [0] https://github.com/containers/toolbox 10 11 Info about test cases: 12 - some tests rely on a certain configuration of a container that is done by 13 executing several commands in the entry-point of a container. To make 14 sure the initialization had enough time to be executed, 15 WaitContainerReady() after the container is started. 16 17 - in several places there's an invocation of 'podman logs' It is there mainly 18 to ease debugging when a test goes wrong (during the initialization of a 19 container) but sometimes it is also used in the test case itself. 20 21 Maintainers (Toolbox Team): 22 - Ondřej Míchal <harrymichal@fedoraproject.org> 23 - Debarshi Ray <rishi@fedoraproject.org> 24 25 Also available on Freenode IRC on #silverblue or #podman 26 */ 27 28 import ( 29 "fmt" 30 "os" 31 "os/exec" 32 "os/user" 33 "path" 34 "strconv" 35 "strings" 36 "syscall" 37 38 "github.com/hanks177/podman/v4/pkg/rootless" 39 . "github.com/hanks177/podman/v4/test/utils" 40 . "github.com/onsi/ginkgo" 41 . "github.com/onsi/gomega" 42 . "github.com/onsi/gomega/gexec" 43 ) 44 45 var _ = Describe("Toolbox-specific testing", func() { 46 var ( 47 tempdir string 48 err error 49 podmanTest *PodmanTestIntegration 50 ) 51 52 BeforeEach(func() { 53 tempdir, err = CreateTempDirInTempDir() 54 if err != nil { 55 os.Exit(1) 56 } 57 podmanTest = PodmanTestCreate(tempdir) 58 podmanTest.Setup() 59 }) 60 61 AfterEach(func() { 62 podmanTest.Cleanup() 63 f := CurrentGinkgoTestDescription() 64 processTestResult(f) 65 }) 66 67 It("podman run --dns=none - allows self-management of /etc/resolv.conf", func() { 68 session := podmanTest.Podman([]string{"run", "--dns", "none", ALPINE, "sh", "-c", 69 "rm -f /etc/resolv.conf; touch -d '1970-01-01 00:02:03' /etc/resolv.conf; stat -c %s:%Y /etc/resolv.conf"}) 70 session.WaitWithDefaultTimeout() 71 Expect(session).Should(Exit(0)) 72 Expect(session.OutputToString()).To(ContainSubstring("0:123")) 73 }) 74 75 It("podman run --no-hosts - allows self-management of /etc/hosts", func() { 76 session := podmanTest.Podman([]string{"run", "--no-hosts", ALPINE, "sh", "-c", 77 "rm -f /etc/hosts; touch -d '1970-01-01 00:02:03' /etc/hosts; stat -c %s:%Y /etc/hosts"}) 78 session.WaitWithDefaultTimeout() 79 Expect(session).Should(Exit(0)) 80 Expect(session.OutputToString()).To(ContainSubstring("0:123")) 81 }) 82 83 It("podman create --ulimit host + podman exec - correctly mirrors hosts ulimits", func() { 84 if podmanTest.RemoteTest { 85 Skip("Ulimit check does not work with a remote client") 86 } 87 var session *PodmanSessionIntegration 88 var containerHardLimit int 89 var rlimit syscall.Rlimit 90 var err error 91 92 err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) 93 Expect(err).To(BeNil()) 94 fmt.Printf("Expected value: %d", rlimit.Max) 95 96 session = podmanTest.Podman([]string{"create", "--name", "test", "--ulimit", "host", ALPINE, 97 "sleep", "1000"}) 98 session.WaitWithDefaultTimeout() 99 Expect(session).Should(Exit(0)) 100 101 session = podmanTest.Podman([]string{"start", "test"}) 102 session.WaitWithDefaultTimeout() 103 Expect(session).Should(Exit(0)) 104 105 session = podmanTest.Podman([]string{"exec", "test", "sh", "-c", 106 "ulimit -H -n"}) 107 session.WaitWithDefaultTimeout() 108 Expect(session).Should(Exit(0)) 109 containerHardLimit, err = strconv.Atoi(strings.Trim(session.OutputToString(), "\n")) 110 Expect(err).To(BeNil()) 111 Expect(containerHardLimit).To(BeNumerically(">=", rlimit.Max)) 112 }) 113 114 It("podman create --ipc=host --pid=host + podman exec - correct shared memory limit size", func() { 115 // Comparison of the size of /dev/shm on the host being equal to the one in 116 // a container 117 if podmanTest.RemoteTest { 118 Skip("Shm size check does not work with a remote client") 119 } 120 SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1") 121 var session *PodmanSessionIntegration 122 var cmd *exec.Cmd 123 var hostShmSize, containerShmSize int 124 var err error 125 126 // Because Alpine uses busybox, most commands don't offer advanced options 127 // like "--output" in df. Therefore the value of the field 'Size' (or 128 // ('1K-blocks') needs to be extracted manually. 129 cmd = exec.Command("df", "/dev/shm") 130 res, err := cmd.Output() 131 Expect(err).To(BeNil()) 132 lines := strings.SplitN(string(res), "\n", 2) 133 fields := strings.Fields(lines[len(lines)-1]) 134 hostShmSize, err = strconv.Atoi(fields[1]) 135 Expect(err).To(BeNil()) 136 137 session = podmanTest.Podman([]string{"create", "--name", "test", "--ipc=host", "--pid=host", ALPINE, 138 "sleep", "1000"}) 139 session.WaitWithDefaultTimeout() 140 Expect(session).Should(Exit(0)) 141 142 session = podmanTest.Podman([]string{"start", "test"}) 143 session.WaitWithDefaultTimeout() 144 Expect(session).Should(Exit(0)) 145 146 session = podmanTest.Podman([]string{"exec", "test", 147 "df", "/dev/shm"}) 148 session.WaitWithDefaultTimeout() 149 Expect(session).Should(Exit(0)) 150 lines = session.OutputToStringArray() 151 fields = strings.Fields(lines[len(lines)-1]) 152 containerShmSize, err = strconv.Atoi(fields[1]) 153 Expect(err).To(BeNil()) 154 155 // In some cases it may happen that the size of /dev/shm is not exactly 156 // equal. Therefore it's fine if there's a slight tolerance between the 157 // compared values. 158 Expect(hostShmSize).To(BeNumerically("~", containerShmSize, 100)) 159 }) 160 161 It("podman create --userns=keep-id --user root:root - entrypoint - entrypoint is executed as root", func() { 162 SkipIfNotRootless("only meaningful when run rootless") 163 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", ALPINE, 164 "id"}) 165 session.WaitWithDefaultTimeout() 166 Expect(session).Should(Exit(0)) 167 Expect(session.OutputToString()).To(ContainSubstring("uid=0(root) gid=0(root)")) 168 }) 169 170 It("podman create --userns=keep-id + podman exec - correct names of user and group", func() { 171 SkipIfNotRootless("only meaningful when run rootless") 172 var session *PodmanSessionIntegration 173 var err error 174 175 currentUser, err := user.Current() 176 Expect(err).To(BeNil()) 177 178 currentGroup, err := user.LookupGroupId(currentUser.Gid) 179 Expect(err).To(BeNil()) 180 181 session = podmanTest.Podman([]string{"create", "--name", "test", "--userns=keep-id", ALPINE, 182 "sleep", "1000"}) 183 session.WaitWithDefaultTimeout() 184 Expect(session).Should(Exit(0)) 185 Expect(err).To(BeNil()) 186 187 session = podmanTest.Podman([]string{"start", "test"}) 188 session.WaitWithDefaultTimeout() 189 Expect(session).Should(Exit(0)) 190 191 expectedOutput := fmt.Sprintf("uid=%s(%s) gid=%s(%s)", 192 currentUser.Uid, currentUser.Username, 193 currentGroup.Gid, currentGroup.Name) 194 195 session = podmanTest.Podman([]string{"exec", "test", 196 "id"}) 197 session.WaitWithDefaultTimeout() 198 Expect(session).Should(Exit(0)) 199 Expect(session.OutputToString()).To(ContainSubstring(expectedOutput)) 200 }) 201 202 It("podman create --userns=keep-id - entrypoint - adding user with useradd and then removing their password", func() { 203 SkipIfNotRootless("only meaningful when run rootless") 204 var session *PodmanSessionIntegration 205 206 var username string = "testuser" 207 var homeDir string = "/home/testuser" 208 var shell string = "/bin/sh" 209 var uid string = "1001" 210 var gid string = "1001" 211 212 useradd := fmt.Sprintf("useradd --home-dir %s --shell %s --uid %s %s", 213 homeDir, shell, uid, username) 214 passwd := fmt.Sprintf("passwd --delete %s", username) 215 session = podmanTest.Podman([]string{"create", "--log-driver", "k8s-file", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c", 216 fmt.Sprintf("%s; %s; echo READY; sleep 1000", useradd, passwd)}) 217 session.WaitWithDefaultTimeout() 218 Expect(session).Should(Exit(0)) 219 220 session = podmanTest.Podman([]string{"start", "test"}) 221 session.WaitWithDefaultTimeout() 222 Expect(session).Should(Exit(0)) 223 224 Expect(WaitContainerReady(podmanTest, "test", "READY", 5, 1)).To(BeTrue()) 225 226 expectedOutput := fmt.Sprintf("%s:x:%s:%s::%s:%s", 227 username, uid, gid, homeDir, shell) 228 229 session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/passwd"}) 230 session.WaitWithDefaultTimeout() 231 Expect(session).Should(Exit(0)) 232 Expect(session.OutputToString()).To(ContainSubstring(expectedOutput)) 233 234 expectedOutput = "passwd: Note: deleting a password also unlocks the password." 235 236 session = podmanTest.Podman([]string{"logs", "test"}) 237 session.WaitWithDefaultTimeout() 238 Expect(session).Should(Exit(0)) 239 Expect(session.ErrorToString()).To(ContainSubstring(expectedOutput)) 240 }) 241 242 It("podman create --userns=keep-id + podman exec - adding group with groupadd", func() { 243 SkipIfNotRootless("only meaningful when run rootless") 244 var session *PodmanSessionIntegration 245 246 var groupName string = "testgroup" 247 var gid string = "1001" 248 249 groupadd := fmt.Sprintf("groupadd --gid %s %s", gid, groupName) 250 251 session = podmanTest.Podman([]string{"create", "--log-driver", "k8s-file", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c", 252 fmt.Sprintf("%s; echo READY; sleep 1000", groupadd)}) 253 session.WaitWithDefaultTimeout() 254 Expect(session).Should(Exit(0)) 255 256 session = podmanTest.Podman([]string{"start", "test"}) 257 session.WaitWithDefaultTimeout() 258 Expect(session).Should(Exit(0)) 259 260 Expect(WaitContainerReady(podmanTest, "test", "READY", 5, 1)).To(BeTrue()) 261 262 session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/group"}) 263 session.WaitWithDefaultTimeout() 264 Expect(session).Should(Exit(0)) 265 Expect(session.OutputToString()).To(ContainSubstring(groupName)) 266 267 session = podmanTest.Podman([]string{"logs", "test"}) 268 session.WaitWithDefaultTimeout() 269 Expect(session).Should(Exit(0)) 270 Expect(session.OutputToString()).To(ContainSubstring("READY")) 271 }) 272 273 It("podman create --userns=keep-id - entrypoint - modifying existing user with usermod - add to new group, change home/shell/uid", func() { 274 SkipIfNotRootless("only meaningful when run rootless") 275 var session *PodmanSessionIntegration 276 var badHomeDir string = "/home/badtestuser" 277 var badShell string = "/bin/sh" 278 var badUID string = "1001" 279 var username string = "testuser" 280 var homeDir string = "/home/testuser" 281 var shell string = "/bin/bash" 282 var uid string = "2000" 283 var groupName string = "testgroup" 284 var gid string = "2000" 285 286 // The use of bad* in the name of variables does not imply the invocation 287 // of useradd should fail The user is supposed to be created successfully 288 // but later his information (uid, home, shell,..) is changed via usermod. 289 useradd := fmt.Sprintf("useradd --home-dir %s --shell %s --uid %s %s", 290 badHomeDir, badShell, badUID, username) 291 groupadd := fmt.Sprintf("groupadd --gid %s %s", 292 gid, groupName) 293 usermod := fmt.Sprintf("usermod --append --groups wheel --home %s --shell %s --uid %s --gid %s %s", 294 homeDir, shell, uid, gid, username) 295 296 session = podmanTest.Podman([]string{"create", "--log-driver", "k8s-file", "--name", "test", "--userns=keep-id", "--user", "root:root", fedoraToolbox, "sh", "-c", 297 fmt.Sprintf("%s; %s; %s; echo READY; sleep 1000", useradd, groupadd, usermod)}) 298 session.WaitWithDefaultTimeout() 299 Expect(session).Should(Exit(0)) 300 301 session = podmanTest.Podman([]string{"start", "test"}) 302 session.WaitWithDefaultTimeout() 303 Expect(session).Should(Exit(0)) 304 305 Expect(WaitContainerReady(podmanTest, "test", "READY", 5, 1)).To(BeTrue()) 306 307 expectedUser := fmt.Sprintf("%s:x:%s:%s::%s:%s", 308 username, uid, gid, homeDir, shell) 309 310 session = podmanTest.Podman([]string{"exec", "test", "cat", "/etc/passwd"}) 311 session.WaitWithDefaultTimeout() 312 Expect(session).Should(Exit(0)) 313 Expect(session.OutputToString()).To(ContainSubstring(expectedUser)) 314 315 session = podmanTest.Podman([]string{"logs", "test"}) 316 session.WaitWithDefaultTimeout() 317 Expect(session).Should(Exit(0)) 318 Expect(session.OutputToString()).To(ContainSubstring("READY")) 319 }) 320 321 It("podman run --privileged --userns=keep-id --user root:root - entrypoint - (bind)mounting", func() { 322 SkipIfNotRootless("only meaningful when run rootless") 323 var session *PodmanSessionIntegration 324 325 session = podmanTest.Podman([]string{"run", "--privileged", "--userns=keep-id", "--user", "root:root", ALPINE, 326 "mount", "-t", "tmpfs", "tmpfs", "/tmp"}) 327 session.WaitWithDefaultTimeout() 328 Expect(session).Should(Exit(0)) 329 330 session = podmanTest.Podman([]string{"run", "--privileged", "--userns=keep-id", "--user", "root:root", ALPINE, 331 "mount", "--rbind", "/tmp", "/var/tmp"}) 332 session.WaitWithDefaultTimeout() 333 Expect(session).Should(Exit(0)) 334 }) 335 336 It("podman create + start - with all needed switches for create - sleep as entry-point", func() { 337 SkipIfNotRootless("only meaningful when run rootless") 338 var session *PodmanSessionIntegration 339 340 // These should be most of the switches that Toolbox uses to create a "toolbox" container 341 // https://github.com/containers/toolbox/blob/master/src/cmd/create.go 342 session = podmanTest.Podman([]string{"create", 343 "--log-driver", "k8s-file", 344 "--dns", "none", 345 "--hostname", "toolbox", 346 "--ipc", "host", 347 "--label", "com.github.containers.toolbox=true", 348 "--name", "test", 349 "--network", "host", 350 "--no-hosts", 351 "--pid", "host", 352 "--privileged", 353 "--security-opt", "label=disable", 354 "--ulimit", "host", 355 "--userns=keep-id", 356 "--user", "root:root", 357 fedoraToolbox, "sh", "-c", "echo READY; sleep 1000"}) 358 session.WaitWithDefaultTimeout() 359 Expect(session).Should(Exit(0)) 360 361 session = podmanTest.Podman([]string{"start", "test"}) 362 session.WaitWithDefaultTimeout() 363 Expect(session).Should(Exit(0)) 364 365 Expect(WaitContainerReady(podmanTest, "test", "READY", 5, 1)).To(BeTrue()) 366 367 session = podmanTest.Podman([]string{"logs", "test"}) 368 session.WaitWithDefaultTimeout() 369 Expect(session).Should(Exit(0)) 370 Expect(session.OutputToString()).To(ContainSubstring("READY")) 371 }) 372 373 It("podman run --userns=keep-id check $HOME", func() { 374 SkipIfNotRootless("only meaningful when run rootless") 375 var session *PodmanSessionIntegration 376 currentUser, err := user.Current() 377 Expect(err).To(BeNil()) 378 379 session = podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:%s", currentUser.HomeDir, currentUser.HomeDir), "--userns=keep-id", fedoraToolbox, "sh", "-c", "echo $HOME"}) 380 session.WaitWithDefaultTimeout() 381 Expect(session).Should(Exit(0)) 382 Expect(session.OutputToString()).To(ContainSubstring(currentUser.HomeDir)) 383 384 if rootless.IsRootless() { 385 location := path.Dir(currentUser.HomeDir) 386 volumeArg := fmt.Sprintf("%s:%s", location, location) 387 session = podmanTest.Podman([]string{"run", 388 "--userns=keep-id", 389 "--volume", volumeArg, 390 fedoraToolbox, "sh", "-c", "echo $HOME"}) 391 session.WaitWithDefaultTimeout() 392 Expect(session).Should(Exit(0)) 393 Expect(session.OutputToString()).To(ContainSubstring(currentUser.HomeDir)) 394 } 395 }) 396 397 })