github.com/containers/podman/v4@v4.9.4/pkg/bindings/test/pods_test.go (about) 1 package bindings_test 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 "time" 8 9 "github.com/containers/podman/v4/libpod/define" 10 "github.com/containers/podman/v4/pkg/bindings" 11 "github.com/containers/podman/v4/pkg/bindings/pods" 12 "github.com/containers/podman/v4/pkg/domain/entities" 13 "github.com/containers/podman/v4/pkg/errorhandling" 14 "github.com/containers/podman/v4/pkg/specgen" 15 "github.com/containers/podman/v4/utils" 16 . "github.com/onsi/ginkgo/v2" 17 . "github.com/onsi/gomega" 18 "github.com/onsi/gomega/gexec" 19 ) 20 21 var _ = Describe("Podman pods", func() { 22 var ( 23 bt *bindingTest 24 s *gexec.Session 25 newpod string 26 err error 27 ) 28 29 BeforeEach(func() { 30 bt = newBindingTest() 31 newpod = "newpod" 32 bt.RestoreImagesFromCache() 33 bt.Podcreate(&newpod) 34 s = bt.startAPIService() 35 time.Sleep(1 * time.Second) 36 err := bt.NewConnection() 37 Expect(err).ToNot(HaveOccurred()) 38 }) 39 40 AfterEach(func() { 41 s.Kill() 42 bt.cleanup() 43 }) 44 45 It("inspect pod", func() { 46 // Inspect an invalid pod name 47 _, err := pods.Inspect(bt.conn, "dummyname", nil) 48 Expect(err).To(HaveOccurred()) 49 code, _ := bindings.CheckResponseCode(err) 50 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 51 52 // Inspect a valid pod name 53 response, err := pods.Inspect(bt.conn, newpod, nil) 54 Expect(err).ToNot(HaveOccurred()) 55 Expect(response.Name).To(Equal(newpod)) 56 }) 57 58 // Test validates the list all api returns 59 It("list pod", func() { 60 // List all the pods in the current instance 61 podSummary, err := pods.List(bt.conn, nil) 62 Expect(err).ToNot(HaveOccurred()) 63 Expect(podSummary).To(HaveLen(1)) 64 65 // Start the pod 66 _, err = pods.Start(bt.conn, newpod, nil) 67 Expect(err).ToNot(HaveOccurred()) 68 69 // Adding an alpine container to the existing pod 70 _, err = bt.RunTopContainer(nil, &newpod) 71 Expect(err).ToNot(HaveOccurred()) 72 podSummary, err = pods.List(bt.conn, nil) 73 // Verify no errors. 74 Expect(err).ToNot(HaveOccurred()) 75 // Verify number of containers in the pod. 76 Expect(podSummary[0].Containers).To(HaveLen(2)) 77 78 // Add multiple pods and verify them by name and size. 79 var newpod2 = "newpod2" 80 bt.Podcreate(&newpod2) 81 podSummary, err = pods.List(bt.conn, nil) 82 Expect(err).ToNot(HaveOccurred(), "Error from pods.List") 83 Expect(podSummary).To(HaveLen(2)) 84 var names []string 85 for _, i := range podSummary { 86 names = append(names, i.Name) 87 } 88 Expect(StringInSlice(newpod, names)).To(BeTrue()) 89 Expect(StringInSlice("newpod2", names)).To(BeTrue()) 90 }) 91 92 // The test validates the list pod endpoint with passing filters as the params. 93 It("List pods with filters", func() { 94 newpod2 := "newpod2" 95 bt.Podcreate(&newpod2) 96 97 // Start the pod 98 _, err = pods.Start(bt.conn, newpod, nil) 99 Expect(err).ToNot(HaveOccurred()) 100 101 _, err = bt.RunTopContainer(nil, &newpod) 102 Expect(err).ToNot(HaveOccurred()) 103 104 // Expected err with invalid filter params 105 filters := make(map[string][]string) 106 filters["dummy"] = []string{"dummy"} 107 options := new(pods.ListOptions).WithFilters(filters) 108 filteredPods, err := pods.List(bt.conn, options) 109 Expect(err).To(HaveOccurred()) 110 Expect(filteredPods).To(BeEmpty(), "len(filteredPods)") 111 code, _ := bindings.CheckResponseCode(err) 112 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 113 114 // Expected empty response with invalid filters 115 filters = make(map[string][]string) 116 filters["name"] = []string{"dummy"} 117 options = new(pods.ListOptions).WithFilters(filters) 118 filteredPods, err = pods.List(bt.conn, options) 119 Expect(err).ToNot(HaveOccurred()) 120 Expect(filteredPods).To(BeEmpty()) 121 122 // Validate list pod with name filter 123 filters = make(map[string][]string) 124 filters["name"] = []string{newpod2} 125 options = new(pods.ListOptions).WithFilters(filters) 126 filteredPods, err = pods.List(bt.conn, options) 127 Expect(err).ToNot(HaveOccurred()) 128 Expect(filteredPods).To(HaveLen(1)) 129 var names []string 130 for _, i := range filteredPods { 131 names = append(names, i.Name) 132 } 133 Expect(StringInSlice("newpod2", names)).To(BeTrue()) 134 135 // Validate list pod with id filter 136 filters = make(map[string][]string) 137 response, err := pods.Inspect(bt.conn, newpod, nil) 138 Expect(err).ToNot(HaveOccurred()) 139 id := response.ID 140 filters["id"] = []string{id} 141 options = new(pods.ListOptions).WithFilters(filters) 142 filteredPods, err = pods.List(bt.conn, options) 143 Expect(err).ToNot(HaveOccurred()) 144 Expect(filteredPods).To(HaveLen(1)) 145 names = names[:0] 146 for _, i := range filteredPods { 147 names = append(names, i.Name) 148 } 149 Expect(StringInSlice("newpod", names)).To(BeTrue()) 150 151 // Using multiple filters 152 filters["name"] = []string{newpod} 153 options = new(pods.ListOptions).WithFilters(filters) 154 filteredPods, err = pods.List(bt.conn, options) 155 Expect(err).ToNot(HaveOccurred()) 156 Expect(filteredPods).To(HaveLen(1)) 157 names = names[:0] 158 for _, i := range filteredPods { 159 names = append(names, i.Name) 160 } 161 Expect(StringInSlice("newpod", names)).To(BeTrue()) 162 }) 163 164 // The test validates if the exists responds 165 It("exists pod", func() { 166 response, err := pods.Exists(bt.conn, "dummyName", nil) 167 Expect(err).ToNot(HaveOccurred()) 168 Expect(response).To(BeFalse()) 169 170 // Should exit with no error and response should be true 171 response, err = pods.Exists(bt.conn, "newpod", nil) 172 Expect(err).ToNot(HaveOccurred()) 173 Expect(response).To(BeTrue()) 174 }) 175 176 // This test validates if All running containers within 177 // each specified pod are paused and unpaused 178 It("pause unpause pod", func() { 179 // TODO fix this 180 Skip("Pod behavior is jacked right now.") 181 // Pause invalid container 182 _, err := pods.Pause(bt.conn, "dummyName", nil) 183 Expect(err).To(HaveOccurred()) 184 code, _ := bindings.CheckResponseCode(err) 185 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 186 187 // Adding an alpine container to the existing pod 188 _, err = bt.RunTopContainer(nil, &newpod) 189 Expect(err).ToNot(HaveOccurred()) 190 191 // Binding needs to be modified to inspect the pod state. 192 // Since we don't have a pod state we inspect the states of the containers within the pod. 193 // Pause a valid container 194 _, err = pods.Pause(bt.conn, newpod, nil) 195 Expect(err).ToNot(HaveOccurred()) 196 response, err := pods.Inspect(bt.conn, newpod, nil) 197 Expect(err).ToNot(HaveOccurred()) 198 Expect(response.State).To(Equal(define.PodStatePaused)) 199 for _, i := range response.Containers { 200 Expect(define.StringToContainerStatus(i.State)). 201 To(Equal(define.ContainerStatePaused)) 202 } 203 204 // Unpause a valid container 205 _, err = pods.Unpause(bt.conn, newpod, nil) 206 Expect(err).ToNot(HaveOccurred()) 207 response, err = pods.Inspect(bt.conn, newpod, nil) 208 Expect(err).ToNot(HaveOccurred()) 209 Expect(response.State).To(Equal(define.PodStateRunning)) 210 for _, i := range response.Containers { 211 Expect(define.StringToContainerStatus(i.State)). 212 To(Equal(define.ContainerStateRunning)) 213 } 214 }) 215 216 It("start pod with port conflict", func() { 217 randomport, err := utils.GetRandomPort() 218 Expect(err).ToNot(HaveOccurred()) 219 220 portPublish := fmt.Sprintf("%d:%d", randomport, randomport) 221 var podwithport = "newpodwithport" 222 bt.PodcreateAndExpose(&podwithport, &portPublish) 223 224 // Start pod and expose port 12345 225 _, err = pods.Start(bt.conn, podwithport, nil) 226 Expect(err).ToNot(HaveOccurred()) 227 228 // Start another pod and expose same port 12345 229 var podwithport2 = "newpodwithport2" 230 bt.PodcreateAndExpose(&podwithport2, &portPublish) 231 232 _, err = pods.Start(bt.conn, podwithport2, nil) 233 Expect(err).To(HaveOccurred()) 234 code, _ := bindings.CheckResponseCode(err) 235 Expect(code).To(BeNumerically("==", http.StatusConflict)) 236 Expect(err).To(BeAssignableToTypeOf(&errorhandling.PodConflictErrorModel{})) 237 }) 238 239 It("start stop restart pod", func() { 240 // Start an invalid pod 241 _, err = pods.Start(bt.conn, "dummyName", nil) 242 Expect(err).To(HaveOccurred()) 243 code, _ := bindings.CheckResponseCode(err) 244 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 245 246 // Stop an invalid pod 247 _, err = pods.Stop(bt.conn, "dummyName", nil) 248 Expect(err).To(HaveOccurred()) 249 code, _ = bindings.CheckResponseCode(err) 250 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 251 252 // Restart an invalid pod 253 _, err = pods.Restart(bt.conn, "dummyName", nil) 254 Expect(err).To(HaveOccurred()) 255 code, _ = bindings.CheckResponseCode(err) 256 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 257 258 // Start a valid pod and inspect status of each container 259 _, err = pods.Start(bt.conn, newpod, nil) 260 Expect(err).ToNot(HaveOccurred()) 261 262 response, err := pods.Inspect(bt.conn, newpod, nil) 263 Expect(err).ToNot(HaveOccurred()) 264 Expect(response.State).To(Equal(define.PodStateRunning)) 265 for _, i := range response.Containers { 266 Expect(define.StringToContainerStatus(i.State)). 267 To(Equal(define.ContainerStateRunning)) 268 } 269 270 // Start an already running pod 271 _, err = pods.Start(bt.conn, newpod, nil) 272 Expect(err).ToNot(HaveOccurred()) 273 274 // Stop the running pods 275 _, err = pods.Stop(bt.conn, newpod, nil) 276 Expect(err).ToNot(HaveOccurred()) 277 response, _ = pods.Inspect(bt.conn, newpod, nil) 278 Expect(response.State).To(Equal(define.PodStateExited)) 279 for _, i := range response.Containers { 280 Expect(define.StringToContainerStatus(i.State)). 281 To(Equal(define.ContainerStateExited)) 282 } 283 284 // Stop an already stopped pod 285 _, err = pods.Stop(bt.conn, newpod, nil) 286 Expect(err).ToNot(HaveOccurred()) 287 288 _, err = pods.Restart(bt.conn, newpod, nil) 289 Expect(err).ToNot(HaveOccurred()) 290 response, _ = pods.Inspect(bt.conn, newpod, nil) 291 Expect(response.State).To(Equal(define.PodStateRunning)) 292 for _, i := range response.Containers { 293 Expect(define.StringToContainerStatus(i.State)). 294 To(Equal(define.ContainerStateRunning)) 295 } 296 }) 297 298 // Test to validate all the pods in the stopped/exited state are pruned successfully. 299 It("prune pod", func() { 300 // Add a new pod 301 var newpod2 = "newpod2" 302 bt.Podcreate(&newpod2) 303 // No pods pruned since no pod in exited state 304 pruneResponse, err := pods.Prune(bt.conn, nil) 305 Expect(err).ToNot(HaveOccurred()) 306 Expect(pruneResponse).To(BeEmpty(), "len(pruneResponse)") 307 podSummary, err := pods.List(bt.conn, nil) 308 Expect(err).ToNot(HaveOccurred()) 309 Expect(podSummary).To(HaveLen(2)) 310 311 // Prune only one pod which is in exited state. 312 // Start then stop a pod. 313 // pod moves to exited state one pod should be pruned now. 314 _, err = pods.Start(bt.conn, newpod, nil) 315 Expect(err).ToNot(HaveOccurred()) 316 _, err = pods.Stop(bt.conn, newpod, nil) 317 Expect(err).ToNot(HaveOccurred()) 318 response, err := pods.Inspect(bt.conn, newpod, nil) 319 Expect(err).ToNot(HaveOccurred()) 320 Expect(response.State).To(Equal(define.PodStateExited)) 321 pruneResponse, err = pods.Prune(bt.conn, nil) 322 Expect(err).ToNot(HaveOccurred()) 323 Expect(pruneResponse).To(HaveLen(1), "len(pruneResponse)") 324 // Validate status and record pod id of pod to be pruned 325 Expect(response.State).To(Equal(define.PodStateExited)) 326 podID := response.ID 327 // Check if right pod was pruned 328 Expect(pruneResponse).To(HaveLen(1)) 329 Expect(pruneResponse[0].Id).To(Equal(podID)) 330 // One pod is pruned hence only one pod should be active. 331 podSummary, err = pods.List(bt.conn, nil) 332 Expect(err).ToNot(HaveOccurred()) 333 Expect(podSummary).To(HaveLen(1)) 334 335 // Test prune multiple pods. 336 bt.Podcreate(&newpod) 337 _, err = pods.Start(bt.conn, newpod, nil) 338 Expect(err).ToNot(HaveOccurred()) 339 _, err = pods.Start(bt.conn, newpod2, nil) 340 Expect(err).ToNot(HaveOccurred()) 341 _, err = pods.Stop(bt.conn, newpod, nil) 342 Expect(err).ToNot(HaveOccurred()) 343 response, err = pods.Inspect(bt.conn, newpod, nil) 344 Expect(err).ToNot(HaveOccurred()) 345 Expect(response.State).To(Equal(define.PodStateExited)) 346 for _, i := range response.Containers { 347 Expect(define.StringToContainerStatus(i.State)). 348 To(Equal(define.ContainerStateExited)) 349 } 350 _, err = pods.Stop(bt.conn, newpod2, nil) 351 Expect(err).ToNot(HaveOccurred()) 352 response, err = pods.Inspect(bt.conn, newpod2, nil) 353 Expect(err).ToNot(HaveOccurred()) 354 Expect(response.State).To(Equal(define.PodStateExited)) 355 for _, i := range response.Containers { 356 Expect(define.StringToContainerStatus(i.State)). 357 To(Equal(define.ContainerStateExited)) 358 } 359 _, err = pods.Prune(bt.conn, nil) 360 Expect(err).ToNot(HaveOccurred()) 361 podSummary, err = pods.List(bt.conn, nil) 362 Expect(err).ToNot(HaveOccurred()) 363 Expect(podSummary).To(BeEmpty()) 364 }) 365 366 It("simple create pod", func() { 367 ps := entities.PodSpec{PodSpecGen: specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}} 368 ps.PodSpecGen.Name = "foobar" 369 _, err := pods.CreatePodFromSpec(bt.conn, &ps) 370 Expect(err).ToNot(HaveOccurred()) 371 372 exists, err := pods.Exists(bt.conn, "foobar", nil) 373 Expect(err).ToNot(HaveOccurred()) 374 Expect(exists).To(BeTrue()) 375 }) 376 377 // Test validates the pod top bindings 378 It("pod top", func() { 379 var name = "podA" 380 381 bt.Podcreate(&name) 382 _, err := pods.Start(bt.conn, name, nil) 383 Expect(err).ToNot(HaveOccurred()) 384 385 // By name 386 _, err = pods.Top(bt.conn, name, nil) 387 Expect(err).ToNot(HaveOccurred()) 388 389 // With descriptors 390 options := new(pods.TopOptions).WithDescriptors([]string{"user,pid,hpid"}) 391 output, err := pods.Top(bt.conn, name, options) 392 Expect(err).ToNot(HaveOccurred()) 393 header := strings.Split(output[0], "\t") 394 for _, d := range []string{"USER", "PID", "HPID"} { 395 Expect(d).To(BeElementOf(header)) 396 } 397 398 // With bogus ID 399 _, err = pods.Top(bt.conn, "IdoNotExist", nil) 400 Expect(err).To(HaveOccurred()) 401 402 // With bogus descriptors 403 options = new(pods.TopOptions).WithDescriptors([]string{"Me,Neither"}) 404 _, err = pods.Top(bt.conn, name, options) 405 Expect(err).To(HaveOccurred()) 406 }) 407 })