github.com/containers/podman/v4@v4.9.4/test/e2e/system_connection_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "net/url" 6 "os" 7 "os/exec" 8 "os/user" 9 "path/filepath" 10 11 "github.com/containers/common/pkg/config" 12 . "github.com/containers/podman/v4/test/utils" 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 . "github.com/onsi/gomega/gbytes" 16 . "github.com/onsi/gomega/gexec" 17 ) 18 19 func setupEmptyContainersConf() { 20 // make sure connections are not written to real user config on host 21 file := filepath.Join(podmanTest.TempDir, "containersconf") 22 f, err := os.Create(file) 23 Expect(err).ToNot(HaveOccurred()) 24 f.Close() 25 os.Setenv("CONTAINERS_CONF", file) 26 } 27 28 var _ = Describe("podman system connection", func() { 29 30 BeforeEach(setupEmptyContainersConf) 31 32 Context("without running API service", func() { 33 It("add ssh://", func() { 34 cmd := []string{"system", "connection", "add", 35 "--default", 36 "--identity", "~/.ssh/id_rsa", 37 "QA", 38 "ssh://root@podman.test:2222/run/podman/podman.sock", 39 } 40 session := podmanTest.Podman(cmd) 41 session.WaitWithDefaultTimeout() 42 Expect(session).Should(ExitCleanly()) 43 Expect(session.Out.Contents()).Should(BeEmpty()) 44 45 cfg, err := config.ReadCustomConfig() 46 Expect(err).ShouldNot(HaveOccurred()) 47 Expect(cfg).Should(HaveActiveService("QA")) 48 Expect(cfg).Should(VerifyService( 49 "QA", 50 "ssh://root@podman.test:2222/run/podman/podman.sock", 51 "~/.ssh/id_rsa", 52 )) 53 54 cmd = []string{"system", "connection", "rename", 55 "QA", 56 "QE", 57 } 58 session = podmanTest.Podman(cmd) 59 session.WaitWithDefaultTimeout() 60 Expect(session).Should(ExitCleanly()) 61 62 Expect(config.ReadCustomConfig()).Should(HaveActiveService("QE")) 63 }) 64 65 It("add UDS", func() { 66 cmd := []string{"system", "connection", "add", 67 "QA-UDS", 68 "unix:///run/podman/podman.sock", 69 } 70 session := podmanTest.Podman(cmd) 71 session.WaitWithDefaultTimeout() 72 Expect(session).Should(Exit(0)) 73 Expect(session.Out.Contents()).Should(BeEmpty()) 74 // stderr will probably warn (ENOENT or EACCESS) about socket 75 // but it's too unreliable to test for. 76 77 Expect(config.ReadCustomConfig()).Should(VerifyService( 78 "QA-UDS", 79 "unix:///run/podman/podman.sock", 80 "", 81 )) 82 83 cmd = []string{"system", "connection", "add", 84 "QA-UDS1", 85 "--socket-path", "/run/user/podman/podman.sock", 86 "unix:///run/podman/podman.sock", 87 } 88 session = podmanTest.Podman(cmd) 89 session.WaitWithDefaultTimeout() 90 Expect(session).Should(Exit(0)) 91 Expect(session.Out.Contents()).Should(BeEmpty()) 92 93 Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA-UDS")) 94 Expect(config.ReadCustomConfig()).Should(VerifyService( 95 "QA-UDS1", 96 "unix:///run/user/podman/podman.sock", 97 "", 98 )) 99 }) 100 101 It("add tcp", func() { 102 cmd := []string{"system", "connection", "add", 103 "QA-TCP", 104 "tcp://localhost:8888", 105 } 106 session := podmanTest.Podman(cmd) 107 session.WaitWithDefaultTimeout() 108 Expect(session).Should(ExitCleanly()) 109 Expect(session.Out.Contents()).Should(BeEmpty()) 110 111 Expect(config.ReadCustomConfig()).Should(VerifyService( 112 "QA-TCP", 113 "tcp://localhost:8888", 114 "", 115 )) 116 }) 117 118 It("add to new farm", func() { 119 cfg, err := config.ReadCustomConfig() 120 Expect(err).ShouldNot(HaveOccurred()) 121 Expect(cfg.Farms.List).Should(BeEmpty()) 122 123 cmd := []string{"system", "connection", "add", 124 "--default", 125 "--identity", "~/.ssh/id_rsa", 126 "--farm", "farm1", 127 "QA", 128 "ssh://root@podman.test:2222/run/podman/podman.sock", 129 } 130 session := podmanTest.Podman(cmd) 131 session.WaitWithDefaultTimeout() 132 Expect(session).Should(ExitCleanly()) 133 Expect(session.Out.Contents()).Should(BeEmpty()) 134 135 cfg, err = config.ReadCustomConfig() 136 Expect(err).ShouldNot(HaveOccurred()) 137 Expect(cfg).Should(HaveActiveService("QA")) 138 Expect(cfg).Should(VerifyService( 139 "QA", 140 "ssh://root@podman.test:2222/run/podman/podman.sock", 141 "~/.ssh/id_rsa", 142 )) 143 Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA"})) 144 }) 145 146 It("add to existing farm", func() { 147 // create empty farm 148 cmd := []string{"farm", "create", "empty-farm"} 149 session := podmanTest.Podman(cmd) 150 session.WaitWithDefaultTimeout() 151 Expect(session).Should(ExitCleanly()) 152 Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"empty-farm\" created")) 153 154 cfg, err := config.ReadCustomConfig() 155 Expect(err).ShouldNot(HaveOccurred()) 156 Expect(cfg.Farms.List).Should(HaveKeyWithValue("empty-farm", []string{})) 157 158 cmd = []string{"system", "connection", "add", 159 "--default", 160 "--identity", "~/.ssh/id_rsa", 161 "--farm", "empty-farm", 162 "QA", 163 "ssh://root@podman.test:2222/run/podman/podman.sock", 164 } 165 session = podmanTest.Podman(cmd) 166 session.WaitWithDefaultTimeout() 167 Expect(session).Should(ExitCleanly()) 168 Expect(session.Out.Contents()).Should(BeEmpty()) 169 170 cfg, err = config.ReadCustomConfig() 171 Expect(err).ShouldNot(HaveOccurred()) 172 Expect(cfg).Should(HaveActiveService("QA")) 173 Expect(cfg).Should(VerifyService( 174 "QA", 175 "ssh://root@podman.test:2222/run/podman/podman.sock", 176 "~/.ssh/id_rsa", 177 )) 178 Expect(cfg.Farms.List).Should(HaveKeyWithValue("empty-farm", []string{"QA"})) 179 }) 180 181 It("removing connection should remove from farm also", func() { 182 cfg, err := config.ReadCustomConfig() 183 Expect(err).ShouldNot(HaveOccurred()) 184 Expect(cfg.Farms.List).Should(BeEmpty()) 185 186 cmd := []string{"system", "connection", "add", 187 "--default", 188 "--identity", "~/.ssh/id_rsa", 189 "--farm", "farm1", 190 "QA", 191 "ssh://root@podman.test:2222/run/podman/podman.sock", 192 } 193 session := podmanTest.Podman(cmd) 194 session.WaitWithDefaultTimeout() 195 Expect(session).Should(ExitCleanly()) 196 Expect(session.Out.Contents()).Should(BeEmpty()) 197 198 cfg, err = config.ReadCustomConfig() 199 Expect(err).ShouldNot(HaveOccurred()) 200 Expect(cfg).Should(HaveActiveService("QA")) 201 Expect(cfg).Should(VerifyService( 202 "QA", 203 "ssh://root@podman.test:2222/run/podman/podman.sock", 204 "~/.ssh/id_rsa", 205 )) 206 Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA"})) 207 208 // Remove the QA connection 209 session = podmanTest.Podman([]string{"system", "connection", "remove", "QA"}) 210 session.WaitWithDefaultTimeout() 211 Expect(session).Should(ExitCleanly()) 212 Expect(session.Out.Contents()).Should(BeEmpty()) 213 214 cfg, err = config.ReadCustomConfig() 215 Expect(err).ShouldNot(HaveOccurred()) 216 Expect(cfg.Engine.ActiveService).Should(BeEmpty()) 217 Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty()) 218 Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{})) 219 }) 220 221 It("remove", func() { 222 session := podmanTest.Podman([]string{"system", "connection", "add", 223 "--default", 224 "--identity", "~/.ssh/id_rsa", 225 "QA", 226 "ssh://root@podman.test:2222/run/podman/podman.sock", 227 }) 228 session.WaitWithDefaultTimeout() 229 Expect(session).Should(ExitCleanly()) 230 231 // two passes to test that removing non-existent connection is not an error 232 for i := 0; i < 2; i++ { 233 session = podmanTest.Podman([]string{"system", "connection", "remove", "QA"}) 234 session.WaitWithDefaultTimeout() 235 Expect(session).Should(ExitCleanly()) 236 Expect(session.Out.Contents()).Should(BeEmpty()) 237 238 cfg, err := config.ReadCustomConfig() 239 Expect(err).ShouldNot(HaveOccurred()) 240 Expect(cfg.Engine.ActiveService).Should(BeEmpty()) 241 Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty()) 242 } 243 }) 244 245 It("remove --all", func() { 246 session := podmanTest.Podman([]string{"system", "connection", "add", 247 "--default", 248 "--identity", "~/.ssh/id_rsa", 249 "QA", 250 "ssh://root@podman.test:2222/run/podman/podman.sock", 251 }) 252 session.WaitWithDefaultTimeout() 253 Expect(session).Should(ExitCleanly()) 254 255 session = podmanTest.Podman([]string{"system", "connection", "remove", "--all"}) 256 session.WaitWithDefaultTimeout() 257 Expect(session).Should(ExitCleanly()) 258 Expect(session.Out.Contents()).Should(BeEmpty()) 259 Expect(session.Err.Contents()).Should(BeEmpty()) 260 261 session = podmanTest.Podman([]string{"system", "connection", "list"}) 262 session.WaitWithDefaultTimeout() 263 Expect(session).Should(ExitCleanly()) 264 }) 265 266 It("default", func() { 267 for _, name := range []string{"devl", "qe"} { 268 cmd := []string{"system", "connection", "add", 269 "--default", 270 "--identity", "~/.ssh/id_rsa", 271 name, 272 "ssh://root@podman.test:2222/run/podman/podman.sock", 273 } 274 session := podmanTest.Podman(cmd) 275 session.WaitWithDefaultTimeout() 276 Expect(session).Should(ExitCleanly()) 277 } 278 279 cmd := []string{"system", "connection", "default", "devl"} 280 session := podmanTest.Podman(cmd) 281 session.WaitWithDefaultTimeout() 282 Expect(session).Should(ExitCleanly()) 283 Expect(session.Out.Contents()).Should(BeEmpty()) 284 285 Expect(config.ReadCustomConfig()).Should(HaveActiveService("devl")) 286 287 cmd = []string{"system", "connection", "list"} 288 session = podmanTest.Podman(cmd) 289 session.WaitWithDefaultTimeout() 290 Expect(session).Should(ExitCleanly()) 291 Expect(session.Out).Should(Say("Name *URI *Identity *Default")) 292 293 cmd = []string{"system", "connection", "list", "--format", "{{.Name}}"} 294 session = podmanTest.Podman(cmd) 295 session.WaitWithDefaultTimeout() 296 Expect(session).Should(ExitCleanly()) 297 Expect(session.OutputToString()).Should(Equal("devl qe")) 298 }) 299 300 It("failed default", func() { 301 cmd := []string{"system", "connection", "default", "devl"} 302 session := podmanTest.Podman(cmd) 303 session.WaitWithDefaultTimeout() 304 Expect(session).ShouldNot(ExitCleanly()) 305 Expect(session.Err).Should(Say("destination is not defined")) 306 }) 307 308 It("failed rename", func() { 309 cmd := []string{"system", "connection", "rename", "devl", "QE"} 310 session := podmanTest.Podman(cmd) 311 session.WaitWithDefaultTimeout() 312 Expect(session).ShouldNot(ExitCleanly()) 313 Expect(session.Err).Should(Say("destination is not defined")) 314 }) 315 316 It("empty list", func() { 317 cmd := []string{"system", "connection", "list"} 318 session := podmanTest.Podman(cmd) 319 session.WaitWithDefaultTimeout() 320 Expect(session).Should(ExitCleanly()) 321 Expect(session.OutputToStringArray()).Should(HaveLen(1)) 322 Expect(session.Err.Contents()).Should(BeEmpty()) 323 }) 324 }) 325 326 Context("sshd and API services required", func() { 327 BeforeEach(func() { 328 // These tests are unique in as much as they require podman, podman-remote, systemd and sshd. 329 // podman-remote commands will be executed by ginkgo directly. 330 SkipIfContainerized("sshd is not available when running in a container") 331 SkipIfRemote("connection heuristic requires both podman and podman-remote binaries") 332 SkipIfNotRootless(fmt.Sprintf("FIXME: set up ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid())) 333 SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running") 334 SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running") 335 }) 336 337 It("add ssh:// socket path using connection heuristic", func() { 338 u, err := user.Current() 339 Expect(err).ShouldNot(HaveOccurred()) 340 341 // Ensure that the remote end uses our built podman 342 if os.Getenv("PODMAN_BINARY") == "" { 343 err = os.Setenv("PODMAN_BINARY", podmanTest.PodmanBinary) 344 Expect(err).ShouldNot(HaveOccurred()) 345 346 defer func() { 347 os.Unsetenv("PODMAN_BINARY") 348 }() 349 } 350 351 cmd := exec.Command(podmanTest.RemotePodmanBinary, 352 "system", "connection", "add", 353 "--default", 354 "--identity", filepath.Join(u.HomeDir, ".ssh", "id_ed25519"), 355 "QA", 356 fmt.Sprintf("ssh://%s@localhost", u.Username)) 357 358 session, err := Start(cmd, GinkgoWriter, GinkgoWriter) 359 Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("%q failed to execute", podmanTest.RemotePodmanBinary)) 360 Eventually(session, DefaultWaitTimeout).Should(Exit(0)) 361 Expect(session.Out.Contents()).Should(BeEmpty()) 362 Expect(session.Err.Contents()).Should(BeEmpty()) 363 364 cmd = exec.Command(podmanTest.RemotePodmanBinary, 365 "--connection", "QA", "ps") 366 _, err = Start(cmd, GinkgoWriter, GinkgoWriter) 367 Expect(err).ToNot(HaveOccurred()) 368 369 // export the container_host env var and try again 370 err = os.Setenv("CONTAINER_HOST", fmt.Sprintf("ssh://%s@localhost", u.Username)) 371 Expect(err).ToNot(HaveOccurred()) 372 defer os.Unsetenv("CONTAINER_HOST") 373 374 cmd = exec.Command(podmanTest.RemotePodmanBinary, "ps") 375 _, err = Start(cmd, GinkgoWriter, GinkgoWriter) 376 Expect(err).ToNot(HaveOccurred()) 377 378 uri := url.URL{ 379 Scheme: "ssh", 380 User: url.User(u.Username), 381 Host: "localhost:22", 382 Path: fmt.Sprintf("/run/user/%s/podman/podman.sock", u.Uid), 383 } 384 385 Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA")) 386 Expect(config.ReadCustomConfig()).Should(VerifyService( 387 "QA", 388 uri.String(), 389 filepath.Join(u.HomeDir, ".ssh", "id_ed25519"), 390 )) 391 }) 392 }) 393 })