github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/bindings/test/images_test.go (about) 1 package bindings_test 2 3 import ( 4 "net/http" 5 "os" 6 "path/filepath" 7 "time" 8 9 "github.com/hanks177/podman/v4/pkg/bindings" 10 "github.com/hanks177/podman/v4/pkg/bindings/containers" 11 "github.com/hanks177/podman/v4/pkg/bindings/images" 12 "github.com/hanks177/podman/v4/pkg/domain/entities" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 . "github.com/onsi/gomega/gexec" 16 . "github.com/onsi/gomega/gstruct" 17 ) 18 19 var _ = Describe("Podman images", func() { 20 var ( 21 // tempdir string 22 // err error 23 // podmanTest *PodmanTestIntegration 24 bt *bindingTest 25 s *Session 26 err error 27 ) 28 29 BeforeEach(func() { 30 // tempdir, err = CreateTempDirInTempDir() 31 // if err != nil { 32 // os.Exit(1) 33 // } 34 // podmanTest = PodmanTestCreate(tempdir) 35 // podmanTest.Setup() 36 // podmanTest.SeedImages() 37 bt = newBindingTest() 38 bt.RestoreImagesFromCache() 39 s = bt.startAPIService() 40 time.Sleep(1 * time.Second) 41 err := bt.NewConnection() 42 Expect(err).ToNot(HaveOccurred()) 43 }) 44 45 AfterEach(func() { 46 // podmanTest.Cleanup() 47 // f := CurrentGinkgoTestDescription() 48 // processTestResult(f) 49 s.Kill() 50 bt.cleanup() 51 }) 52 53 It("inspect image", func() { 54 // Inspect invalid image be 404 55 _, err = images.GetImage(bt.conn, "foobar5000", nil) 56 Expect(err).ToNot(BeNil()) 57 code, _ := bindings.CheckResponseCode(err) 58 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 59 60 // Inspect by short name 61 data, err := images.GetImage(bt.conn, alpine.shortName, nil) 62 Expect(err).ToNot(HaveOccurred()) 63 64 // Inspect with full ID 65 _, err = images.GetImage(bt.conn, data.ID, nil) 66 Expect(err).ToNot(HaveOccurred()) 67 68 // Inspect with partial ID 69 _, err = images.GetImage(bt.conn, data.ID[0:12], nil) 70 Expect(err).ToNot(HaveOccurred()) 71 72 // Inspect by long name 73 _, err = images.GetImage(bt.conn, alpine.name, nil) 74 Expect(err).ToNot(HaveOccurred()) 75 // TODO it looks like the images API always returns size regardless 76 // of bool or not. What should we do ? 77 // Expect(data.Size).To(BeZero()) 78 79 options := new(images.GetOptions).WithSize(true) 80 // Enabling the size parameter should result in size being populated 81 data, err = images.GetImage(bt.conn, alpine.name, options) 82 Expect(err).ToNot(HaveOccurred()) 83 Expect(data.Size).To(BeNumerically(">", 0)) 84 }) 85 86 // Test to validate the remove image api 87 It("remove image", func() { 88 // NOTE that removing an image that does not exist will still 89 // return a 200 http status. The response, however, includes 90 // the exit code that podman-remote should exit with. 91 // 92 // The libpod/images/remove endpoint supports batch removal of 93 // images for performance reasons and for hiding the logic of 94 // deciding which exit code to use from the client. 95 response, errs := images.Remove(bt.conn, []string{"foobar5000"}, nil) 96 Expect(len(errs)).To(BeNumerically(">", 0)) 97 Expect(response.ExitCode).To(BeNumerically("==", 1)) // podman-remote would exit with 1 98 99 // Remove an image by name, validate image is removed and error is nil 100 inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) 101 Expect(err).ToNot(HaveOccurred()) 102 response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil) 103 Expect(len(errs)).To(BeZero()) 104 105 Expect(inspectData.ID).To(Equal(response.Deleted[0])) 106 _, err = images.GetImage(bt.conn, busybox.shortName, nil) 107 code, _ := bindings.CheckResponseCode(err) 108 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 109 110 // Start a container with alpine image 111 var top string = "top" 112 _, err = bt.RunTopContainer(&top, nil) 113 Expect(err).ToNot(HaveOccurred()) 114 // we should now have a container called "top" running 115 containerResponse, err := containers.Inspect(bt.conn, "top", nil) 116 Expect(err).ToNot(HaveOccurred()) 117 Expect(containerResponse.Name).To(Equal("top")) 118 119 // try to remove the image "alpine". This should fail since we are not force 120 // deleting hence image cannot be deleted until the container is deleted. 121 _, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil) 122 code, _ = bindings.CheckResponseCode(errs[0]) 123 // FIXME FIXME FIXME: #12441: another invalid error 124 // FIXME FIXME FIXME: this time msg="Image used by SHA: ..." 125 Expect(code).To(BeNumerically("==", -1)) 126 127 // Removing the image "alpine" where force = true 128 options := new(images.RemoveOptions).WithForce(true) 129 _, errs = images.Remove(bt.conn, []string{alpine.shortName}, options) 130 Expect(errs).To(Or(HaveLen(0), BeNil())) 131 // To be extra sure, check if the previously created container 132 // is gone as well. 133 _, err = containers.Inspect(bt.conn, "top", nil) 134 code, _ = bindings.CheckResponseCode(err) 135 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 136 137 // Now make sure both images are gone. 138 _, err = images.GetImage(bt.conn, busybox.shortName, nil) 139 code, _ = bindings.CheckResponseCode(err) 140 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 141 142 _, err = images.GetImage(bt.conn, alpine.shortName, nil) 143 code, _ = bindings.CheckResponseCode(err) 144 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 145 }) 146 147 // Tests to validate the image tag command. 148 It("tag image", func() { 149 150 // Validates if invalid image name is given a bad response is encountered. 151 err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName, nil) 152 Expect(err).ToNot(BeNil()) 153 code, _ := bindings.CheckResponseCode(err) 154 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 155 156 // Validates if the image is tagged successfully. 157 err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil) 158 Expect(err).ToNot(HaveOccurred()) 159 160 // Validates if name updates when the image is retagged. 161 _, err := images.GetImage(bt.conn, "alpine:demo", nil) 162 Expect(err).ToNot(HaveOccurred()) 163 164 }) 165 166 // Test to validate the List images command. 167 It("List image", func() { 168 // Array to hold the list of images returned 169 imageSummary, err := images.List(bt.conn, nil) 170 // There Should be no errors in the response. 171 Expect(err).ToNot(HaveOccurred()) 172 // Since in the begin context two images are created the 173 // list context should have only 2 images 174 Expect(len(imageSummary)).To(Equal(2)) 175 176 // Adding one more image. There Should be no errors in the response. 177 // And the count should be three now. 178 bt.Pull("testimage:20200929") 179 imageSummary, err = images.List(bt.conn, nil) 180 Expect(err).ToNot(HaveOccurred()) 181 Expect(len(imageSummary)).To(BeNumerically(">=", 2)) 182 183 // Validate the image names. 184 var names []string 185 for _, i := range imageSummary { 186 names = append(names, i.RepoTags...) 187 } 188 Expect(names).To(ContainElement(alpine.name)) 189 Expect(names).To(ContainElement(busybox.name)) 190 191 // List images with a filter 192 filters := make(map[string][]string) 193 filters["reference"] = []string{alpine.name} 194 options := new(images.ListOptions).WithFilters(filters).WithAll(false) 195 filteredImages, err := images.List(bt.conn, options) 196 Expect(err).ToNot(HaveOccurred()) 197 Expect(len(filteredImages)).To(BeNumerically("==", 1)) 198 199 // List images with a bad filter 200 filters["name"] = []string{alpine.name} 201 options = new(images.ListOptions).WithFilters(filters) 202 _, err = images.List(bt.conn, options) 203 Expect(err).ToNot(BeNil()) 204 code, _ := bindings.CheckResponseCode(err) 205 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 206 }) 207 208 It("Image Exists", func() { 209 // exists on bogus image should be false, with no error 210 exists, err := images.Exists(bt.conn, "foobar", nil) 211 Expect(err).ToNot(HaveOccurred()) 212 Expect(exists).To(BeFalse()) 213 214 // exists with shortname should be true 215 exists, err = images.Exists(bt.conn, alpine.shortName, nil) 216 Expect(err).ToNot(HaveOccurred()) 217 Expect(exists).To(BeTrue()) 218 219 // exists with fqname should be true 220 exists, err = images.Exists(bt.conn, alpine.name, nil) 221 Expect(err).ToNot(HaveOccurred()) 222 Expect(exists).To(BeTrue()) 223 }) 224 225 It("Load|Import Image", func() { 226 // load an image 227 _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) 228 Expect(len(errs)).To(BeZero()) 229 exists, err := images.Exists(bt.conn, alpine.name, nil) 230 Expect(err).ToNot(HaveOccurred()) 231 Expect(exists).To(BeFalse()) 232 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 233 Expect(err).ToNot(HaveOccurred()) 234 defer f.Close() 235 names, err := images.Load(bt.conn, f) 236 Expect(err).ToNot(HaveOccurred()) 237 Expect(names.Names[0]).To(Equal(alpine.name)) 238 exists, err = images.Exists(bt.conn, alpine.name, nil) 239 Expect(err).ToNot(HaveOccurred()) 240 Expect(exists).To(BeTrue()) 241 242 // load with a repo name 243 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 244 Expect(err).ToNot(HaveOccurred()) 245 _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) 246 Expect(len(errs)).To(BeZero()) 247 exists, err = images.Exists(bt.conn, alpine.name, nil) 248 Expect(err).ToNot(HaveOccurred()) 249 Expect(exists).To(BeFalse()) 250 names, err = images.Load(bt.conn, f) 251 Expect(err).ToNot(HaveOccurred()) 252 Expect(names.Names[0]).To(Equal(alpine.name)) 253 254 // load with a bad repo name should trigger a 500 255 _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) 256 Expect(len(errs)).To(BeZero()) 257 exists, err = images.Exists(bt.conn, alpine.name, nil) 258 Expect(err).ToNot(HaveOccurred()) 259 Expect(exists).To(BeFalse()) 260 }) 261 262 It("Export Image", func() { 263 // Export an image 264 exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName) 265 w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) 266 Expect(err).ToNot(HaveOccurred()) 267 defer w.Close() 268 err = images.Export(bt.conn, []string{alpine.name}, w, nil) 269 Expect(err).ToNot(HaveOccurred()) 270 _, err = os.Stat(exportPath) 271 Expect(err).ToNot(HaveOccurred()) 272 273 // TODO how do we verify that a format change worked? 274 }) 275 276 It("Import Image", func() { 277 // load an image 278 _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) 279 Expect(len(errs)).To(BeZero()) 280 exists, err := images.Exists(bt.conn, alpine.name, nil) 281 Expect(err).ToNot(HaveOccurred()) 282 Expect(exists).To(BeFalse()) 283 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 284 Expect(err).ToNot(HaveOccurred()) 285 defer f.Close() 286 changes := []string{"CMD /bin/foobar"} 287 testMessage := "test_import" 288 options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name) 289 _, err = images.Import(bt.conn, f, options) 290 Expect(err).ToNot(HaveOccurred()) 291 exists, err = images.Exists(bt.conn, alpine.name, nil) 292 Expect(err).ToNot(HaveOccurred()) 293 Expect(exists).To(BeTrue()) 294 data, err := images.GetImage(bt.conn, alpine.name, nil) 295 Expect(err).ToNot(HaveOccurred()) 296 Expect(data.Comment).To(Equal(testMessage)) 297 298 }) 299 300 It("History Image", func() { 301 // a bogus name should return a 404 302 _, err := images.History(bt.conn, "foobar", nil) 303 Expect(err).To(Not(BeNil())) 304 code, _ := bindings.CheckResponseCode(err) 305 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 306 307 var foundID bool 308 data, err := images.GetImage(bt.conn, alpine.name, nil) 309 Expect(err).ToNot(HaveOccurred()) 310 history, err := images.History(bt.conn, alpine.name, nil) 311 Expect(err).ToNot(HaveOccurred()) 312 for _, i := range history { 313 if i.ID == data.ID { 314 foundID = true 315 break 316 } 317 } 318 Expect(foundID).To(BeTrue()) 319 }) 320 321 It("Search for an image", func() { 322 reports, err := images.Search(bt.conn, "alpine", nil) 323 Expect(err).ToNot(HaveOccurred()) 324 Expect(len(reports)).To(BeNumerically(">", 1)) 325 var foundAlpine bool 326 for _, i := range reports { 327 if i.Name == "docker.io/library/alpine" { 328 foundAlpine = true 329 break 330 } 331 } 332 Expect(foundAlpine).To(BeTrue()) 333 334 // Search for alpine with a limit of 10 335 options := new(images.SearchOptions).WithLimit(10) 336 reports, err = images.Search(bt.conn, "docker.io/alpine", options) 337 Expect(err).ToNot(HaveOccurred()) 338 Expect(len(reports)).To(BeNumerically("<=", 10)) 339 340 filters := make(map[string][]string) 341 filters["stars"] = []string{"100"} 342 // Search for alpine with stars greater than 100 343 options = new(images.SearchOptions).WithFilters(filters) 344 reports, err = images.Search(bt.conn, "docker.io/alpine", options) 345 Expect(err).ToNot(HaveOccurred()) 346 for _, i := range reports { 347 Expect(i.Stars).To(BeNumerically(">=", 100)) 348 } 349 350 // Search with a fqdn 351 reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil) 352 Expect(err).To(BeNil(), "Error in images.Search()") 353 Expect(len(reports)).To(BeNumerically(">=", 1)) 354 }) 355 356 It("Prune images", func() { 357 options := new(images.PruneOptions).WithAll(true) 358 results, err := images.Prune(bt.conn, options) 359 Expect(err).NotTo(HaveOccurred()) 360 Expect(len(results)).To(BeNumerically(">", 0)) 361 }) 362 363 // TODO: we really need to extent to pull tests once we have a more sophisticated CI. 364 It("Image Pull", func() { 365 rawImage := "docker.io/library/busybox:latest" 366 367 pulledImages, err := images.Pull(bt.conn, rawImage, nil) 368 Expect(err).NotTo(HaveOccurred()) 369 Expect(len(pulledImages)).To(Equal(1)) 370 371 exists, err := images.Exists(bt.conn, rawImage, nil) 372 Expect(err).NotTo(HaveOccurred()) 373 Expect(exists).To(BeTrue()) 374 375 // Make sure the normalization AND the full-transport reference works. 376 _, err = images.Pull(bt.conn, "docker://"+rawImage, nil) 377 Expect(err).NotTo(HaveOccurred()) 378 379 // The v2 endpoint only supports the docker transport. Let's see if that's really true. 380 _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil) 381 Expect(err).To(HaveOccurred()) 382 }) 383 384 It("Build no options", func() { 385 results, err := images.Build(bt.conn, []string{"fixture/Containerfile"}, entities.BuildOptions{}) 386 Expect(err).ToNot(HaveOccurred()) 387 Expect(*results).To(MatchFields(IgnoreMissing, Fields{ 388 "ID": Not(BeEmpty()), 389 })) 390 }) 391 })