podman

Форк
0
/
manifest_test.go 
758 строк · 32.2 Кб
1
package integration
2

3
import (
4
	"encoding/json"
5
	"os"
6
	"path/filepath"
7
	"strings"
8

9
	"github.com/containers/common/libimage/define"
10
	podmanRegistry "github.com/containers/podman/v5/hack/podman-registry-go"
11
	. "github.com/containers/podman/v5/test/utils"
12
	"github.com/containers/storage/pkg/archive"
13
	. "github.com/onsi/ginkgo/v2"
14
	. "github.com/onsi/gomega"
15
	. "github.com/onsi/gomega/gexec"
16
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
17
)
18

19
// validateManifestHasAllArchs checks that the specified manifest has all
20
// the archs in `imageList`
21
func validateManifestHasAllArchs(path string) error {
22
	data, err := os.ReadFile(path)
23
	if err != nil {
24
		return err
25
	}
26
	var result struct {
27
		Manifests []struct {
28
			Platform struct {
29
				Architecture string
30
			}
31
		}
32
	}
33
	if err := json.Unmarshal(data, &result); err != nil {
34
		return err
35
	}
36
	archs := map[string]bool{
37
		"amd64":   false,
38
		"arm64":   false,
39
		"ppc64le": false,
40
		"s390x":   false,
41
	}
42
	for _, m := range result.Manifests {
43
		archs[m.Platform.Architecture] = true
44
	}
45
	return nil
46
}
47

48
// Internal function to verify instance compression
49
func verifyInstanceCompression(descriptor []imgspecv1.Descriptor, compression string, arch string) bool {
50
	for _, instance := range descriptor {
51
		if instance.Platform.Architecture != arch {
52
			continue
53
		}
54
		if compression == "zstd" {
55
			// if compression is zstd annotations must contain
56
			val, ok := instance.Annotations["io.github.containers.compression.zstd"]
57
			if ok && val == "true" {
58
				return true
59
			}
60
		} else if len(instance.Annotations) == 0 {
61
			return true
62
		}
63
	}
64
	return false
65
}
66

67
var _ = Describe("Podman manifest", func() {
68

69
	const (
70
		imageList                      = "docker://quay.io/libpod/testimage:00000004"
71
		imageListInstance              = "docker://quay.io/libpod/testimage@sha256:1385ce282f3a959d0d6baf45636efe686c1e14c3e7240eb31907436f7bc531fa"
72
		imageListARM64InstanceDigest   = "sha256:1385ce282f3a959d0d6baf45636efe686c1e14c3e7240eb31907436f7bc531fa"
73
		imageListAMD64InstanceDigest   = "sha256:1462c8e885d567d534d82004656c764263f98deda813eb379689729658a133fb"
74
		imageListPPC64LEInstanceDigest = "sha256:9b7c3300f5f7cfe94e3101a28d1f0a28728f8dbc854fb16dd545b7e5aa351785"
75
		imageListS390XInstanceDigest   = "sha256:cb68b7bfd2f4f7d36006efbe3bef04b57a343e0839588476ca336d9ff9240dbf"
76
	)
77

78
	It("create w/o image and attempt push w/o dest", func() {
79
		for _, amend := range []string{"--amend", "-a"} {
80
			session := podmanTest.Podman([]string{"manifest", "create", "foo"})
81
			session.WaitWithDefaultTimeout()
82
			Expect(session).Should(ExitCleanly())
83

84
			session = podmanTest.Podman([]string{"manifest", "create", "foo"})
85
			session.WaitWithDefaultTimeout()
86
			Expect(session).To(ExitWithError())
87

88
			session = podmanTest.Podman([]string{"manifest", "push", "--all", "foo"})
89
			session.WaitWithDefaultTimeout()
90
			Expect(session).To(ExitWithError())
91
			// Push should actually fail since its not valid registry
92
			Expect(session.ErrorToString()).To(ContainSubstring("requested access to the resource is denied"))
93
			Expect(session.OutputToString()).To(Not(ContainSubstring("accepts 2 arg(s), received 1")))
94

95
			session = podmanTest.Podman([]string{"manifest", "create", amend, "foo"})
96
			session.WaitWithDefaultTimeout()
97
			Expect(session).Should(ExitCleanly())
98

99
			session = podmanTest.Podman([]string{"manifest", "rm", "foo"})
100
			session.WaitWithDefaultTimeout()
101
			Expect(session).Should(ExitCleanly())
102
		}
103
	})
104

105
	It("create w/ image", func() {
106
		session := podmanTest.Podman([]string{"manifest", "create", "foo", imageList})
107
		session.WaitWithDefaultTimeout()
108
		Expect(session).Should(ExitCleanly())
109
	})
110

111
	It("inspect", func() {
112
		session := podmanTest.Podman([]string{"manifest", "inspect", BB})
113
		session.WaitWithDefaultTimeout()
114
		Expect(session).Should(ExitCleanly())
115

116
		session = podmanTest.Podman([]string{"manifest", "inspect", "quay.io/libpod/busybox"})
117
		session.WaitWithDefaultTimeout()
118
		Expect(session).Should(ExitCleanly())
119

120
		// inspect manifest of single image
121
		session = podmanTest.Podman([]string{"manifest", "inspect", "quay.io/libpod/busybox@sha256:6655df04a3df853b029a5fac8836035ac4fab117800c9a6c4b69341bb5306c3d"})
122
		session.WaitWithDefaultTimeout()
123
		Expect(session).Should(Exit(0))
124
		// yet another warning message that is not seen by remote client
125
		stderr := session.ErrorToString()
126
		if IsRemote() {
127
			Expect(stderr).Should(Equal(""))
128
		} else {
129
			Expect(stderr).Should(ContainSubstring("The manifest type application/vnd.docker.distribution.manifest.v2+json is not a manifest list but a single image."))
130
		}
131
	})
132

133
	It("add w/ inspect", func() {
134
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
135
		session.WaitWithDefaultTimeout()
136
		Expect(session).Should(ExitCleanly())
137
		id := strings.TrimSpace(string(session.Out.Contents()))
138

139
		session = podmanTest.Podman([]string{"manifest", "inspect", id})
140
		session.WaitWithDefaultTimeout()
141
		Expect(session).Should(ExitCleanly())
142

143
		session = podmanTest.Podman([]string{"manifest", "add", "--arch=arm64", "foo", imageListInstance})
144
		session.WaitWithDefaultTimeout()
145
		Expect(session).Should(ExitCleanly())
146

147
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
148
		session.WaitWithDefaultTimeout()
149
		Expect(session).Should(ExitCleanly())
150
		Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest))
151
	})
152

153
	It("add with new version", func() {
154
		// Following test must pass for both podman and podman-remote
155
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
156
		session.WaitWithDefaultTimeout()
157
		Expect(session).Should(ExitCleanly())
158
		id := strings.TrimSpace(string(session.Out.Contents()))
159

160
		session = podmanTest.Podman([]string{"manifest", "inspect", id})
161
		session.WaitWithDefaultTimeout()
162
		Expect(session).Should(ExitCleanly())
163

164
		session = podmanTest.Podman([]string{"manifest", "add", "--os-version", "7.7.7", "foo", imageListInstance})
165
		session.WaitWithDefaultTimeout()
166
		Expect(session).Should(ExitCleanly())
167

168
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
169
		session.WaitWithDefaultTimeout()
170
		Expect(session).Should(ExitCleanly())
171
		Expect(session.OutputToString()).To(ContainSubstring("7.7.7"))
172
	})
173

174
	It("tag", func() {
175
		session := podmanTest.Podman([]string{"manifest", "create", "foobar"})
176
		session.WaitWithDefaultTimeout()
177
		Expect(session).Should(ExitCleanly())
178
		session = podmanTest.Podman([]string{"manifest", "add", "foobar", "quay.io/libpod/busybox"})
179
		session.WaitWithDefaultTimeout()
180
		Expect(session).Should(ExitCleanly())
181
		session = podmanTest.Podman([]string{"tag", "foobar", "foobar2"})
182
		session.WaitWithDefaultTimeout()
183
		Expect(session).Should(ExitCleanly())
184
		session = podmanTest.Podman([]string{"manifest", "inspect", "foobar"})
185
		session.WaitWithDefaultTimeout()
186
		Expect(session).Should(ExitCleanly())
187
		session2 := podmanTest.Podman([]string{"manifest", "inspect", "foobar2"})
188
		session2.WaitWithDefaultTimeout()
189
		Expect(session2).Should(ExitCleanly())
190
		Expect(session2.OutputToString()).To(Equal(session.OutputToString()))
191
	})
192

193
	It("push with --add-compression and --force-compression", func() {
194
		if podmanTest.Host.Arch == "ppc64le" {
195
			Skip("No registry image for ppc64le")
196
		}
197
		if isRootless() {
198
			err := podmanTest.RestoreArtifact(REGISTRY_IMAGE)
199
			Expect(err).ToNot(HaveOccurred())
200
		}
201
		lock := GetPortLock("5007")
202
		defer lock.Unlock()
203
		session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5007:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
204
		session.WaitWithDefaultTimeout()
205
		Expect(session).Should(ExitCleanly())
206

207
		if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
208
			Skip("Cannot start docker registry.")
209
		}
210

211
		session = podmanTest.Podman([]string{"build", "-q", "--platform", "linux/amd64", "-t", "imageone", "build/basicalpine"})
212
		session.WaitWithDefaultTimeout()
213
		Expect(session).Should(ExitCleanly())
214

215
		session = podmanTest.Podman([]string{"build", "-q", "--platform", "linux/arm64", "-t", "imagetwo", "build/basicalpine"})
216
		session.WaitWithDefaultTimeout()
217
		Expect(session).Should(ExitCleanly())
218

219
		session = podmanTest.Podman([]string{"manifest", "create", "foobar"})
220
		session.WaitWithDefaultTimeout()
221
		Expect(session).Should(ExitCleanly())
222
		session = podmanTest.Podman([]string{"manifest", "add", "foobar", "containers-storage:localhost/imageone:latest"})
223
		session.WaitWithDefaultTimeout()
224
		Expect(session).Should(ExitCleanly())
225
		session = podmanTest.Podman([]string{"manifest", "add", "foobar", "containers-storage:localhost/imagetwo:latest"})
226
		session.WaitWithDefaultTimeout()
227
		Expect(session).Should(ExitCleanly())
228

229
		push := podmanTest.Podman([]string{"manifest", "push", "--all", "--compression-format", "gzip", "--add-compression", "zstd", "--tls-verify=false", "--remove-signatures", "foobar", "localhost:5007/list"})
230
		push.WaitWithDefaultTimeout()
231
		Expect(push).Should(Exit(0))
232
		output := push.ErrorToString()
233
		// 4 images must be pushed two for gzip and two for zstd
234
		Expect(output).To(ContainSubstring("Copying 4 images generated from 2 images in list"))
235

236
		session = podmanTest.Podman([]string{"run", "--rm", "--net", "host", "quay.io/skopeo/stable", "inspect", "--tls-verify=false", "--raw", "docker://localhost:5007/list:latest"})
237
		session.WaitWithDefaultTimeout()
238
		Expect(session).Should(Exit(0))
239
		var index imgspecv1.Index
240
		inspectData := []byte(session.OutputToString())
241
		err := json.Unmarshal(inspectData, &index)
242
		Expect(err).ToNot(HaveOccurred())
243

244
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "amd64")).Should(BeTrue())
245
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "arm64")).Should(BeTrue())
246
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "arm64")).Should(BeTrue())
247
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "amd64")).Should(BeTrue())
248

249
		// Note: Pushing again with --force-compression should produce the correct response the since blobs will be correctly force-pushed again.
250
		push = podmanTest.Podman([]string{"manifest", "push", "--all", "--add-compression", "zstd", "--tls-verify=false", "--compression-format", "gzip", "--force-compression", "--remove-signatures", "foobar", "localhost:5007/list"})
251
		push.WaitWithDefaultTimeout()
252
		Expect(push).Should(Exit(0))
253
		output = push.ErrorToString()
254
		// 4 images must be pushed two for gzip and two for zstd
255
		Expect(output).To(ContainSubstring("Copying 4 images generated from 2 images in list"))
256

257
		session = podmanTest.Podman([]string{"run", "--rm", "--net", "host", "quay.io/skopeo/stable", "inspect", "--tls-verify=false", "--raw", "docker://localhost:5007/list:latest"})
258
		session.WaitWithDefaultTimeout()
259
		Expect(session).Should(ExitCleanly())
260
		inspectData = []byte(session.OutputToString())
261
		err = json.Unmarshal(inspectData, &index)
262
		Expect(err).ToNot(HaveOccurred())
263

264
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "amd64")).Should(BeTrue())
265
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "arm64")).Should(BeTrue())
266
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "arm64")).Should(BeTrue())
267
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "amd64")).Should(BeTrue())
268

269
		// same thing with add_compression from config file should work and without --add-compression flag in CLI
270
		confFile := filepath.Join(podmanTest.TempDir, "containers.conf")
271
		err = os.WriteFile(confFile, []byte(`[engine]
272
add_compression = ["zstd"]`), 0o644)
273
		Expect(err).ToNot(HaveOccurred())
274
		os.Setenv("CONTAINERS_CONF", confFile)
275

276
		push = podmanTest.Podman([]string{"manifest", "push", "--all", "--tls-verify=false", "--compression-format", "gzip", "--force-compression", "--remove-signatures", "foobar", "localhost:5007/list"})
277
		push.WaitWithDefaultTimeout()
278
		Expect(push).Should(Exit(0))
279
		output = push.ErrorToString()
280
		// 4 images must be pushed two for gzip and two for zstd
281
		Expect(output).To(ContainSubstring("Copying 4 images generated from 2 images in list"))
282

283
		session = podmanTest.Podman([]string{"run", "--rm", "--net", "host", "quay.io/skopeo/stable", "inspect", "--tls-verify=false", "--raw", "docker://localhost:5007/list:latest"})
284
		session.WaitWithDefaultTimeout()
285
		Expect(session).Should(ExitCleanly())
286
		inspectData = []byte(session.OutputToString())
287
		err = json.Unmarshal(inspectData, &index)
288
		Expect(err).ToNot(HaveOccurred())
289

290
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "amd64")).Should(BeTrue())
291
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "arm64")).Should(BeTrue())
292
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "arm64")).Should(BeTrue())
293
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "amd64")).Should(BeTrue())
294

295
		// Note: Pushing again with --force-compression=false should produce in-correct/wrong result since blobs are already present in registry so they will be reused
296
		// ignoring our compression priority ( this is expected behaviour of c/image and --force-compression is introduced to mitigate this behaviour ).
297
		push = podmanTest.Podman([]string{"manifest", "push", "--all", "--add-compression", "zstd", "--force-compression=false", "--tls-verify=false", "--remove-signatures", "foobar", "localhost:5007/list"})
298
		push.WaitWithDefaultTimeout()
299
		Expect(push).Should(Exit(0))
300
		output = push.ErrorToString()
301
		// 4 images must be pushed two for gzip and two for zstd
302
		Expect(output).To(ContainSubstring("Copying 4 images generated from 2 images in list"))
303

304
		session = podmanTest.Podman([]string{"run", "--rm", "--net", "host", "quay.io/skopeo/stable", "inspect", "--tls-verify=false", "--raw", "docker://localhost:5007/list:latest"})
305
		session.WaitWithDefaultTimeout()
306
		Expect(session).Should(ExitCleanly())
307
		inspectData = []byte(session.OutputToString())
308
		err = json.Unmarshal(inspectData, &index)
309
		Expect(err).ToNot(HaveOccurred())
310

311
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "amd64")).Should(BeTrue())
312
		Expect(verifyInstanceCompression(index.Manifests, "zstd", "arm64")).Should(BeTrue())
313
		// blobs of zstd will be wrongly reused for gzip instances without --force-compression
314
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "arm64")).Should(BeFalse())
315
		// blobs of zstd will be wrongly reused for gzip instances without --force-compression
316
		Expect(verifyInstanceCompression(index.Manifests, "gzip", "amd64")).Should(BeFalse())
317
	})
318

319
	It("add --all", func() {
320
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
321
		session.WaitWithDefaultTimeout()
322
		Expect(session).Should(ExitCleanly())
323
		session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList})
324
		session.WaitWithDefaultTimeout()
325
		Expect(session).Should(ExitCleanly())
326
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
327
		session.WaitWithDefaultTimeout()
328
		Expect(session).Should(ExitCleanly())
329
		Expect(session.OutputToString()).To(
330
			And(
331
				ContainSubstring(imageListAMD64InstanceDigest),
332
				ContainSubstring(imageListARM64InstanceDigest),
333
				ContainSubstring(imageListPPC64LEInstanceDigest),
334
				ContainSubstring(imageListS390XInstanceDigest),
335
			))
336
	})
337

338
	It("add --annotation", func() {
339
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
340
		session.WaitWithDefaultTimeout()
341
		Expect(session).Should(ExitCleanly())
342
		session = podmanTest.Podman([]string{"manifest", "add", "--annotation", "hoge", "foo", imageList})
343
		session.WaitWithDefaultTimeout()
344
		Expect(session).Should(Exit(125))
345
		Expect(session.ErrorToString()).To(ContainSubstring("no value given for annotation"))
346
		session = podmanTest.Podman([]string{"manifest", "add", "--annotation", "hoge=fuga", "--annotation", "key=val,withcomma", "foo", imageList})
347
		session.WaitWithDefaultTimeout()
348
		Expect(session).Should(ExitCleanly())
349
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
350
		session.WaitWithDefaultTimeout()
351
		Expect(session).Should(ExitCleanly())
352

353
		var inspect define.ManifestListData
354
		err := json.Unmarshal(session.Out.Contents(), &inspect)
355
		Expect(err).ToNot(HaveOccurred())
356
		Expect(inspect.Manifests[0].Annotations).To(Equal(map[string]string{"hoge": "fuga", "key": "val,withcomma"}))
357
	})
358

359
	It("add --os", func() {
360
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
361
		session.WaitWithDefaultTimeout()
362
		Expect(session).Should(ExitCleanly())
363
		session = podmanTest.Podman([]string{"manifest", "add", "--os", "bar", "foo", imageList})
364
		session.WaitWithDefaultTimeout()
365
		Expect(session).Should(ExitCleanly())
366
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
367
		session.WaitWithDefaultTimeout()
368
		Expect(session).Should(ExitCleanly())
369
		Expect(session.OutputToString()).To(ContainSubstring(`"os": "bar"`))
370
	})
371

372
	It("annotate", func() {
373
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
374
		session.WaitWithDefaultTimeout()
375
		Expect(session).Should(ExitCleanly())
376
		session = podmanTest.Podman([]string{"manifest", "add", "foo", imageListInstance})
377
		session.WaitWithDefaultTimeout()
378
		Expect(session).Should(ExitCleanly())
379
		session = podmanTest.Podman([]string{"manifest", "annotate", "--annotation", "hello=world,withcomma", "--arch", "bar", "foo", imageListARM64InstanceDigest})
380
		session.WaitWithDefaultTimeout()
381
		Expect(session).Should(ExitCleanly())
382
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
383
		session.WaitWithDefaultTimeout()
384
		Expect(session).Should(ExitCleanly())
385
		Expect(session.OutputToString()).To(ContainSubstring(`"architecture": "bar"`))
386
		// Check added annotation
387
		Expect(session.OutputToString()).To(ContainSubstring(`"hello": "world,withcomma"`))
388
	})
389

390
	It("remove digest", func() {
391
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
392
		session.WaitWithDefaultTimeout()
393
		Expect(session).Should(ExitCleanly())
394
		session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList})
395
		session.WaitWithDefaultTimeout()
396
		Expect(session).Should(ExitCleanly())
397
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
398
		session.WaitWithDefaultTimeout()
399
		Expect(session).Should(ExitCleanly())
400
		Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest))
401
		session = podmanTest.Podman([]string{"manifest", "remove", "foo", imageListARM64InstanceDigest})
402
		session.WaitWithDefaultTimeout()
403
		Expect(session).Should(ExitCleanly())
404
		session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
405
		session.WaitWithDefaultTimeout()
406
		Expect(session).Should(ExitCleanly())
407
		Expect(session.OutputToString()).To(
408
			And(
409
				ContainSubstring(imageListAMD64InstanceDigest),
410
				ContainSubstring(imageListPPC64LEInstanceDigest),
411
				ContainSubstring(imageListS390XInstanceDigest),
412
				Not(
413
					ContainSubstring(imageListARM64InstanceDigest)),
414
			))
415
	})
416

417
	It("remove not-found", func() {
418
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
419
		session.WaitWithDefaultTimeout()
420
		Expect(session).Should(ExitCleanly())
421
		session = podmanTest.Podman([]string{"manifest", "add", "foo", imageList})
422
		session.WaitWithDefaultTimeout()
423
		Expect(session).Should(ExitCleanly())
424
		session = podmanTest.Podman([]string{"manifest", "remove", "foo", "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"})
425
		session.WaitWithDefaultTimeout()
426
		Expect(session).To(ExitWithError())
427

428
		session = podmanTest.Podman([]string{"manifest", "rm", "foo"})
429
		session.WaitWithDefaultTimeout()
430
		Expect(session).Should(ExitCleanly())
431
	})
432

433
	It("push --all", func() {
434
		SkipIfRemote("manifest push to dir not supported in remote mode")
435
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
436
		session.WaitWithDefaultTimeout()
437
		Expect(session).Should(ExitCleanly())
438
		session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList})
439
		session.WaitWithDefaultTimeout()
440
		Expect(session).Should(ExitCleanly())
441
		dest := filepath.Join(podmanTest.TempDir, "pushed")
442
		err := os.MkdirAll(dest, os.ModePerm)
443
		Expect(err).ToNot(HaveOccurred())
444
		defer func() {
445
			os.RemoveAll(dest)
446
		}()
447
		session = podmanTest.Podman([]string{"manifest", "push", "-q", "--all", "foo", "dir:" + dest})
448
		session.WaitWithDefaultTimeout()
449
		Expect(session).Should(ExitCleanly())
450

451
		err = validateManifestHasAllArchs(filepath.Join(dest, "manifest.json"))
452
		Expect(err).ToNot(HaveOccurred())
453
	})
454

455
	It("push", func() {
456
		SkipIfRemote("manifest push to dir not supported in remote mode")
457
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
458
		session.WaitWithDefaultTimeout()
459
		Expect(session).Should(ExitCleanly())
460
		session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList})
461
		session.WaitWithDefaultTimeout()
462
		Expect(session).Should(ExitCleanly())
463
		dest := filepath.Join(podmanTest.TempDir, "pushed")
464
		err := os.MkdirAll(dest, os.ModePerm)
465
		Expect(err).ToNot(HaveOccurred())
466
		defer func() {
467
			os.RemoveAll(dest)
468
		}()
469
		session = podmanTest.Podman([]string{"push", "-q", "foo", "dir:" + dest})
470
		session.WaitWithDefaultTimeout()
471
		Expect(session).Should(ExitCleanly())
472

473
		err = validateManifestHasAllArchs(filepath.Join(dest, "manifest.json"))
474
		Expect(err).ToNot(HaveOccurred())
475
	})
476

477
	It("push with compression-format and compression-level", func() {
478
		SkipIfRemote("manifest push to dir not supported in remote mode")
479
		dockerfile := `FROM ` + CITEST_IMAGE + `
480
RUN touch /file
481
`
482
		podmanTest.BuildImage(dockerfile, "localhost/test", "false")
483

484
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
485
		session.WaitWithDefaultTimeout()
486
		Expect(session).Should(ExitCleanly())
487

488
		session = podmanTest.Podman([]string{"manifest", "add", "foo", "containers-storage:localhost/test"})
489
		session.WaitWithDefaultTimeout()
490
		Expect(session).Should(ExitCleanly())
491

492
		// Invalid compression format specified, it must fail
493
		tmpDir := filepath.Join(podmanTest.TempDir, "wrong-compression")
494
		session = podmanTest.Podman([]string{"manifest", "push", "--compression-format", "gzip", "--compression-level", "50", "foo", "oci:" + tmpDir})
495
		session.WaitWithDefaultTimeout()
496
		Expect(session).Should(Exit(125))
497
		output := session.ErrorToString()
498
		Expect(output).To(ContainSubstring("invalid compression level"))
499

500
		dest := filepath.Join(podmanTest.TempDir, "pushed")
501
		err := os.MkdirAll(dest, os.ModePerm)
502
		Expect(err).ToNot(HaveOccurred())
503
		defer func() {
504
			os.RemoveAll(dest)
505
		}()
506
		session = podmanTest.Podman([]string{"push", "-q", "--compression-format=zstd", "foo", "oci:" + dest})
507
		session.WaitWithDefaultTimeout()
508
		Expect(session).Should(ExitCleanly())
509

510
		foundZstdFile := false
511

512
		blobsDir := filepath.Join(dest, "blobs", "sha256")
513

514
		blobs, err := os.ReadDir(blobsDir)
515
		Expect(err).ToNot(HaveOccurred())
516

517
		for _, f := range blobs {
518
			blobPath := filepath.Join(blobsDir, f.Name())
519

520
			sourceFile, err := os.ReadFile(blobPath)
521
			Expect(err).ToNot(HaveOccurred())
522

523
			compressionType := archive.DetectCompression(sourceFile)
524
			if compressionType == archive.Zstd {
525
				foundZstdFile = true
526
				break
527
			}
528
		}
529
		Expect(foundZstdFile).To(BeTrue(), "found zstd file")
530
	})
531

532
	It("push progress", func() {
533
		SkipIfRemote("manifest push to dir not supported in remote mode")
534

535
		session := podmanTest.Podman([]string{"manifest", "create", "foo", imageList})
536
		session.WaitWithDefaultTimeout()
537
		Expect(session).Should(ExitCleanly())
538

539
		dest := filepath.Join(podmanTest.TempDir, "pushed")
540
		err := os.MkdirAll(dest, os.ModePerm)
541
		Expect(err).ToNot(HaveOccurred())
542
		defer func() {
543
			os.RemoveAll(dest)
544
		}()
545

546
		session = podmanTest.Podman([]string{"push", "foo", "-q", "dir:" + dest})
547
		session.WaitWithDefaultTimeout()
548
		Expect(session).Should(ExitCleanly())
549
		Expect(session.ErrorToString()).To(BeEmpty())
550

551
		session = podmanTest.Podman([]string{"push", "foo", "dir:" + dest})
552
		session.WaitWithDefaultTimeout()
553
		Expect(session).Should(Exit(0))
554
		output := session.ErrorToString()
555
		Expect(output).To(ContainSubstring("Writing manifest list to image destination"))
556
		Expect(output).To(ContainSubstring("Storing list signatures"))
557
	})
558

559
	It("push must retry", func() {
560
		SkipIfRemote("warning is not relayed in remote setup")
561
		session := podmanTest.Podman([]string{"manifest", "create", "foo", imageList})
562
		session.WaitWithDefaultTimeout()
563
		Expect(session).Should(ExitCleanly())
564

565
		push := podmanTest.Podman([]string{"manifest", "push", "--all", "--tls-verify=false", "--remove-signatures", "foo", "localhost:7000/bogus"})
566
		push.WaitWithDefaultTimeout()
567
		Expect(push).Should(Exit(125))
568
		Expect(push.ErrorToString()).To(MatchRegexp("Copying blob.*Failed, retrying in 1s \\.\\.\\. \\(1/3\\).*Copying blob.*Failed, retrying in 2s"))
569
	})
570

571
	It("authenticated push", func() {
572
		registryOptions := &podmanRegistry.Options{
573
			PodmanPath: podmanTest.PodmanBinary,
574
			PodmanArgs: podmanTest.MakeOptions(nil, false, false),
575
			Image:      "docker-archive:" + imageTarPath(REGISTRY_IMAGE),
576
		}
577

578
		// Special case for remote: invoke local podman, with all
579
		// network/storage/other args
580
		if IsRemote() {
581
			registryOptions.PodmanArgs = getRemoteOptions(podmanTest, nil)
582
		}
583
		registry, err := podmanRegistry.StartWithOptions(registryOptions)
584
		Expect(err).ToNot(HaveOccurred())
585
		defer func() {
586
			err := registry.Stop()
587
			Expect(err).ToNot(HaveOccurred())
588
		}()
589

590
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
591
		session.WaitWithDefaultTimeout()
592
		Expect(session).Should(ExitCleanly())
593

594
		session = podmanTest.Podman([]string{"tag", CITEST_IMAGE, "localhost:" + registry.Port + "/citest:latest"})
595
		session.WaitWithDefaultTimeout()
596
		Expect(session).Should(ExitCleanly())
597

598
		push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--creds=" + registry.User + ":" + registry.Password, "--format=v2s2", "localhost:" + registry.Port + "/citest:latest"})
599
		push.WaitWithDefaultTimeout()
600
		// Cannot ExitCleanly() because this sometimes warns "Failed, retrying in 1s"
601
		Expect(push).Should(Exit(0))
602

603
		session = podmanTest.Podman([]string{"manifest", "add", "--tls-verify=false", "--creds=" + registry.User + ":" + registry.Password, "foo", "localhost:" + registry.Port + "/citest:latest"})
604
		session.WaitWithDefaultTimeout()
605
		Expect(session).Should(ExitCleanly())
606

607
		push = podmanTest.Podman([]string{"manifest", "push", "--tls-verify=false", "--creds=" + registry.User + ":" + registry.Password, "foo", "localhost:" + registry.Port + "/credstest"})
608
		push.WaitWithDefaultTimeout()
609
		Expect(push).Should(Exit(0))
610
		output := push.ErrorToString()
611
		Expect(output).To(ContainSubstring("Copying blob "))
612
		Expect(output).To(ContainSubstring("Copying config "))
613
		Expect(output).To(ContainSubstring("Writing manifest to image destination"))
614

615
		push = podmanTest.Podman([]string{"manifest", "push", "--compression-format=gzip", "--compression-level=2", "--tls-verify=false", "--creds=podmantest:wrongpasswd", "foo", "localhost:" + registry.Port + "/credstest"})
616
		push.WaitWithDefaultTimeout()
617
		Expect(push).To(ExitWithError())
618
		Expect(push.ErrorToString()).To(ContainSubstring(": authentication required"))
619

620
		// push --rm after pull image (#15033)
621
		push = podmanTest.Podman([]string{"manifest", "push", "-q", "--rm", "--tls-verify=false", "--creds=" + registry.User + ":" + registry.Password, "foo", "localhost:" + registry.Port + "/rmtest"})
622
		push.WaitWithDefaultTimeout()
623
		Expect(push).Should(ExitCleanly())
624

625
		session = podmanTest.Podman([]string{"images", "-q", "foo"})
626
		session.WaitWithDefaultTimeout()
627
		Expect(session).Should(ExitCleanly())
628
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
629
	})
630

631
	It("push with error", func() {
632
		session := podmanTest.Podman([]string{"manifest", "push", "badsrcvalue", "baddestvalue"})
633
		session.WaitWithDefaultTimeout()
634
		Expect(session).Should(ExitWithError())
635
		Expect(session.ErrorToString()).To(ContainSubstring("retrieving local image from image name badsrcvalue: badsrcvalue: image not known"))
636
	})
637

638
	It("push --rm to local directory", func() {
639
		SkipIfRemote("manifest push to dir not supported in remote mode")
640
		session := podmanTest.Podman([]string{"manifest", "create", "foo"})
641
		session.WaitWithDefaultTimeout()
642
		Expect(session).Should(ExitCleanly())
643
		session = podmanTest.Podman([]string{"manifest", "add", "foo", imageList})
644
		session.WaitWithDefaultTimeout()
645
		Expect(session).Should(ExitCleanly())
646
		dest := filepath.Join(podmanTest.TempDir, "pushed")
647
		err := os.MkdirAll(dest, os.ModePerm)
648
		Expect(err).ToNot(HaveOccurred())
649
		defer func() {
650
			os.RemoveAll(dest)
651
		}()
652
		session = podmanTest.Podman([]string{"manifest", "push", "-q", "--purge", "foo", "dir:" + dest})
653
		session.WaitWithDefaultTimeout()
654
		Expect(session).Should(ExitCleanly())
655
		session = podmanTest.Podman([]string{"manifest", "push", "-p", "foo", "dir:" + dest})
656
		session.WaitWithDefaultTimeout()
657
		Expect(session).Should(Exit(125))
658
		Expect(session.ErrorToString()).To(ContainSubstring("retrieving local image from image name foo: foo: image not known"))
659
		session = podmanTest.Podman([]string{"images", "-q", "foo"})
660
		session.WaitWithDefaultTimeout()
661
		Expect(session).Should(ExitCleanly())
662
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
663

664
		// push --rm after pull image (#15033)
665
		session = podmanTest.Podman([]string{"pull", "-q", "quay.io/libpod/testdigest_v2s2"})
666
		session.WaitWithDefaultTimeout()
667
		Expect(session).Should(ExitCleanly())
668

669
		session = podmanTest.Podman([]string{"manifest", "create", "bar"})
670
		session.WaitWithDefaultTimeout()
671
		Expect(session).Should(ExitCleanly())
672
		session = podmanTest.Podman([]string{"manifest", "add", "bar", "quay.io/libpod/testdigest_v2s2"})
673
		session.WaitWithDefaultTimeout()
674
		Expect(session).Should(ExitCleanly())
675
		session = podmanTest.Podman([]string{"manifest", "push", "-q", "--rm", "bar", "dir:" + dest})
676
		session.WaitWithDefaultTimeout()
677
		Expect(session).Should(ExitCleanly())
678
		session = podmanTest.Podman([]string{"images", "-q", "bar"})
679
		session.WaitWithDefaultTimeout()
680
		Expect(session).Should(ExitCleanly())
681
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
682

683
		session = podmanTest.Podman([]string{"manifest", "rm", "foo", "bar"})
684
		session.WaitWithDefaultTimeout()
685
		Expect(session).Should(ExitWithError())
686
		Expect(session.ErrorToString()).To(ContainSubstring("foo: image not known"))
687
		Expect(session.ErrorToString()).To(ContainSubstring("bar: image not known"))
688
	})
689

690
	It("exists", func() {
691
		manifestList := "manifest-list"
692
		session := podmanTest.Podman([]string{"manifest", "create", manifestList})
693
		session.WaitWithDefaultTimeout()
694
		Expect(session).Should(ExitCleanly())
695

696
		session = podmanTest.Podman([]string{"manifest", "exists", manifestList})
697
		session.WaitWithDefaultTimeout()
698
		Expect(session).Should(ExitCleanly())
699

700
		session = podmanTest.Podman([]string{"manifest", "exists", "no-manifest"})
701
		session.WaitWithDefaultTimeout()
702
		Expect(session).Should(Exit(1))
703
	})
704

705
	It("rm should not remove referenced images", func() {
706
		manifestList := "manifestlist"
707
		imageName := "quay.io/libpod/busybox"
708

709
		session := podmanTest.Podman([]string{"pull", "-q", imageName})
710
		session.WaitWithDefaultTimeout()
711
		Expect(session).Should(ExitCleanly())
712

713
		session = podmanTest.Podman([]string{"manifest", "create", manifestList})
714
		session.WaitWithDefaultTimeout()
715
		Expect(session).Should(ExitCleanly())
716

717
		session = podmanTest.Podman([]string{"manifest", "add", manifestList, imageName})
718
		session.WaitWithDefaultTimeout()
719
		Expect(session).Should(ExitCleanly())
720

721
		session = podmanTest.Podman([]string{"manifest", "rm", manifestList})
722
		session.WaitWithDefaultTimeout()
723
		Expect(session).Should(ExitCleanly())
724

725
		// image should still show up
726
		session = podmanTest.Podman([]string{"image", "exists", imageName})
727
		session.WaitWithDefaultTimeout()
728
		Expect(session).Should(ExitCleanly())
729
	})
730

731
	It("manifest rm should not remove image and should be able to remove tagged manifest list", func() {
732
		// manifest rm should fail with `image is not a manifest list`
733
		session := podmanTest.Podman([]string{"manifest", "rm", ALPINE})
734
		session.WaitWithDefaultTimeout()
735
		Expect(session).Should(Exit(125))
736
		Expect(session.ErrorToString()).To(ContainSubstring("image is not a manifest list"))
737

738
		manifestName := "testmanifest:sometag"
739
		session = podmanTest.Podman([]string{"manifest", "create", manifestName})
740
		session.WaitWithDefaultTimeout()
741
		Expect(session).Should(ExitCleanly())
742

743
		// verify if manifest exists
744
		session = podmanTest.Podman([]string{"manifest", "exists", manifestName})
745
		session.WaitWithDefaultTimeout()
746
		Expect(session).Should(ExitCleanly())
747

748
		// manifest rm should be able to remove tagged manifest list
749
		session = podmanTest.Podman([]string{"manifest", "rm", manifestName})
750
		session.WaitWithDefaultTimeout()
751
		Expect(session).Should(ExitCleanly())
752

753
		// verify that manifest should not exist
754
		session = podmanTest.Podman([]string{"manifest", "exists", manifestName})
755
		session.WaitWithDefaultTimeout()
756
		Expect(session).Should(Exit(1))
757
	})
758
})
759

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.