From 5621f5199d0aeaefae77db920866d7aeea9d1e7b Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 23 Apr 2020 15:36:47 -0400 Subject: Manifest remove, push Implements podman manifest remove and podman manifest push. Signed-off-by: Qi Wang --- cmd/podman/manifest/manifest.go | 4 +- cmd/podman/manifest/push.go | 66 +++++++++++++++++ cmd/podman/manifest/remove.go | 47 ++++++++++++ completions/bash/podman | 55 +++++++++++++- docs/source/markdown/podman-manifest-add.1.md | 2 +- docs/source/markdown/podman-manifest-create.1.md | 2 +- docs/source/markdown/podman-manifest-inspect.1.md | 2 +- docs/source/markdown/podman-manifest-push.1.md | 72 +++++++++++++++++++ docs/source/markdown/podman-manifest-remove.1.md | 23 ++++++ docs/source/markdown/podman-manifest.1.md | 4 +- pkg/domain/entities/engine_image.go | 2 + pkg/domain/entities/manifest.go | 5 ++ pkg/domain/infra/abi/manifest.go | 71 ++++++++++++++++++ pkg/domain/infra/tunnel/manifest.go | 15 ++++ test/e2e/manifest_test.go | 88 +++++++++++++++++++++++ 15 files changed, 452 insertions(+), 6 deletions(-) create mode 100644 cmd/podman/manifest/push.go create mode 100644 cmd/podman/manifest/remove.go create mode 100644 docs/source/markdown/podman-manifest-push.1.md create mode 100644 docs/source/markdown/podman-manifest-remove.1.md diff --git a/cmd/podman/manifest/manifest.go b/cmd/podman/manifest/manifest.go index 88d264c1f..d7f042a56 100644 --- a/cmd/podman/manifest/manifest.go +++ b/cmd/podman/manifest/manifest.go @@ -18,7 +18,9 @@ var ( Example: `podman manifest add mylist:v1.11 image:v1.11-amd64 podman manifest create localhost/list podman manifest inspect localhost/list - podman manifest annotate --annotation left=right mylist:v1.11 image:v1.11-amd64`, + podman manifest annotate --annotation left=right mylist:v1.11 image:v1.11-amd64 + podman manifest push mylist:v1.11 quay.io/myimagelist + podman manifest remove mylist:v1.11 sha256:15352d97781ffdf357bf3459c037be3efac4133dc9070c2dce7eca7c05c3e736`, } ) diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go new file mode 100644 index 000000000..49c76f40b --- /dev/null +++ b/cmd/podman/manifest/push.go @@ -0,0 +1,66 @@ +package manifest + +import ( + "context" + + "github.com/containers/common/pkg/auth" + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + manifestPushOpts = entities.ManifestPushOptions{} + pushCmd = &cobra.Command{ + Use: "push [flags] SOURCE DESTINATION", + Short: "Push a manifest list or image index to a registry", + Long: "Pushes manifest lists and image indexes to registries.", + RunE: push, + Example: `podman manifest push mylist:v1.11 quay.io/myimagelist`, + Args: cobra.ExactArgs(2), + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: pushCmd, + Parent: manifestCmd, + }) + flags := pushCmd.Flags() + flags.BoolVar(&manifestPushOpts.Purge, "purge", false, "remove the manifest list if push succeeds") + flags.BoolVar(&manifestPushOpts.All, "all", false, "also push the images in the list") + flags.StringVar(&manifestPushOpts.Authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + flags.StringVar(&manifestPushOpts.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry") + flags.StringVar(&manifestPushOpts.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") + flags.StringVar(&manifestPushOpts.DigestFile, "digestfile", "", "after copying the image, write the digest of the resulting digest to the file") + flags.StringVarP(&manifestPushOpts.Format, "format", "f", "", "manifest type (oci or v2s2) to attempt to use when pushing the manifest list (default is manifest type of source)") + flags.BoolVarP(&manifestPushOpts.RemoveSignatures, "remove-signatures", "", false, "don't copy signatures when pushing images") + flags.StringVar(&manifestPushOpts.SignBy, "sign-by", "", "sign the image using a GPG key with the specified `FINGERPRINT`") + flags.BoolVar(&manifestPushOpts.TlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") + flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists") + if registry.IsRemote() { + _ = flags.MarkHidden("authfile") + _ = flags.MarkHidden("cert-dir") + _ = flags.MarkHidden("tls-verify") + } +} + +func push(cmd *cobra.Command, args []string) error { + if err := auth.CheckAuthFile(manifestPushOpts.Authfile); err != nil { + return err + } + listImageSpec := args[0] + destSpec := args[1] + if listImageSpec == "" { + return errors.Errorf(`invalid image name "%s"`, listImageSpec) + } + if destSpec == "" { + return errors.Errorf(`invalid destination "%s"`, destSpec) + } + if err := registry.ImageEngine().ManifestPush(context.Background(), args, manifestPushOpts); err != nil { + return errors.Wrapf(err, "error pushing manifest %s to %s", listImageSpec, destSpec) + } + return nil +} diff --git a/cmd/podman/manifest/remove.go b/cmd/podman/manifest/remove.go new file mode 100644 index 000000000..4d345efc0 --- /dev/null +++ b/cmd/podman/manifest/remove.go @@ -0,0 +1,47 @@ +package manifest + +import ( + "context" + "fmt" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + removeCmd = &cobra.Command{ + Use: "remove [flags] LIST IMAGE", + Short: "Remove an entry from a manifest list or image index", + Long: "Removes an image from a manifest list or image index.", + RunE: remove, + Example: `podman manifest remove mylist:v1.11 sha256:15352d97781ffdf357bf3459c037be3efac4133dc9070c2dce7eca7c05c3e736`, + Args: cobra.ExactArgs(2), + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: removeCmd, + Parent: manifestCmd, + }) +} + +func remove(cmd *cobra.Command, args []string) error { + listImageSpec := args[0] + instanceSpec := args[1] + if listImageSpec == "" { + return errors.Errorf(`invalid image name "%s"`, listImageSpec) + } + if instanceSpec == "" { + return errors.Errorf(`invalid image digest "%s"`, instanceSpec) + } + updatedListID, err := registry.ImageEngine().ManifestRemove(context.Background(), args) + if err != nil { + return errors.Wrapf(err, "error removing from manifest list %s", listImageSpec) + } + fmt.Printf("%s\n", updatedListID) + return nil +} diff --git a/completions/bash/podman b/completions/bash/podman index 61af7ac59..1e29a2e30 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1742,7 +1742,9 @@ _podman_manifest() { add create inspect - " + push + remove + " __podman_subcommands "$subcommands" && return case "$cur" in @@ -1838,6 +1840,57 @@ _podman_manifest_inspect() { esac } +_podman_manifest_push() { + local options_with_args=" + --authfile + --cert-dir + --creds + --digestfile + --format + -f + --sign-by + --signature-policy, + " + + local boolean_options=" + --all + --purge + --help + -h + --remove-signatures + --tls-verify + --quiet + " + + _complete_ "$options_with_args" "$boolean_options" + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; + esac +} + +_podman_manifest_remove() { + local options_with_args=" + " + + local boolean_options=" + " + + _complete_ "$options_with_args" "$boolean_options" + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + *) + __podman_complete_images --id + ;; + esac +} + _podman_pull() { local options_with_args=" --authfile diff --git a/docs/source/markdown/podman-manifest-add.1.md b/docs/source/markdown/podman-manifest-add.1.md index 857a98e12..82f2071b9 100644 --- a/docs/source/markdown/podman-manifest-add.1.md +++ b/docs/source/markdown/podman-manifest-add.1.md @@ -73,4 +73,4 @@ podman manifest add --arch arm64 --variant v8 mylist:v1.11 docker://71c201d10fff ``` ## SEE ALSO -podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-rmi(1) +podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-manifest-push(1), podman-manifest-remove(1), podman-rmi(1) diff --git a/docs/source/markdown/podman-manifest-create.1.md b/docs/source/markdown/podman-manifest-create.1.md index 941e70c32..537a641f2 100644 --- a/docs/source/markdown/podman-manifest-create.1.md +++ b/docs/source/markdown/podman-manifest-create.1.md @@ -40,4 +40,4 @@ podman manifest create --all mylist:v1.11 docker://fedora ``` ## SEE ALSO -podman(1), podman-manifest(1), podman-manifest-add(1), podman-manifest-inspect(1), podman-rmi(1) +podman(1), podman-manifest(1), podman-manifest-add(1), podman-manifest-inspect(1), podman-manifest-push(1), podman-manifest-remove(1), podman-rmi(1) diff --git a/docs/source/markdown/podman-manifest-inspect.1.md b/docs/source/markdown/podman-manifest-inspect.1.md index efde02643..a4c58bd13 100644 --- a/docs/source/markdown/podman-manifest-inspect.1.md +++ b/docs/source/markdown/podman-manifest-inspect.1.md @@ -21,4 +21,4 @@ podman manifest inspect mylist:v1.11 ``` ## SEE ALSO -podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-add(1), podman-rmi(1) +podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-add(1), podman-manifest-push(1), podman-manifest-remove(1), podman-rmi(1) diff --git a/docs/source/markdown/podman-manifest-push.1.md b/docs/source/markdown/podman-manifest-push.1.md new file mode 100644 index 000000000..38d0c5904 --- /dev/null +++ b/docs/source/markdown/podman-manifest-push.1.md @@ -0,0 +1,72 @@ +% podman-manifest-push(1) + +## NAME +podman\-manifest\-push - Push a manifest list or image index to a registry + +## SYNOPSIS +**podman manifest push** [options...] *listnameorindexname* *transport:details* + +## DESCRIPTION +Pushes a manifest list or image index to a registry. + +## RETURN VALUE +The list image's ID and the digest of the image's manifest. + +## OPTIONS + +**--all** + +Push the images mentioned in the manifest list or image index, in addition to +the list or index itself. + +**--authfile** *path* + +Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. +If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. (Not available for remote commands) + +Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE +environment variable. `export REGISTRY_AUTH_FILE=path` + +**--cert-dir** *path* + +Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. +Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) + +**--creds** *creds* + +The [username[:password]] to use to authenticate with the registry if required. +If one or both values are not supplied, a command line prompt will appear and the +value can be entered. The password is entered without echo. + +**--digestfile** *Digestfile* + +After copying the image, write the digest of the resulting image to the file. + +**--format, -f** + +Manifest list type (oci or v2s2) to use when pushing the list (default is oci). + +**--purge** + +Delete the manifest list or image index from local storage if pushing succeeds. + +**--remove-signatures** + +Don't copy signatures when pushing images. + +**--sign-by** *fingerprint* + +Sign the pushed images using the GPG key that matches the specified fingerprint. + +**--tls-verify** *bool-value* + +Require HTTPS and verify certificates when talking to container registries (defaults to true) (Not available for remote commands) + +## EXAMPLE + +``` +podman manifest push mylist:v1.11 docker://registry.example.org/mylist:v1.11 +``` + +## SEE ALSO +podman(1), podman-manifest(1), podman-manifest-add(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-manifest-remove(1), podman-rmi(1) diff --git a/docs/source/markdown/podman-manifest-remove.1.md b/docs/source/markdown/podman-manifest-remove.1.md new file mode 100644 index 000000000..c13714195 --- /dev/null +++ b/docs/source/markdown/podman-manifest-remove.1.md @@ -0,0 +1,23 @@ +% podman-manifest-remove(1) + +## NAME +podman\-manifest\-remove - Remove an image from a manifest list or image index + +## SYNOPSIS +**podman manifest remove** *listnameorindexname* *transport:details* + +## DESCRIPTION +Removes the image with the specified digest from the specified manifest list or image index. + +## RETURN VALUE +The list image's ID and the digest of the removed image's manifest. + +## EXAMPLE + +``` +podman manifest remove mylist:v1.11 sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221 +e604eabaaee4858232761b4fef84e2316ed8f93e15eceafce845966ee3400036 :sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221 +``` + +## SEE ALSO +podman(1), podman-manifest(1), podman-manifest-add(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-manifest-push(1), podman-rmi(1) diff --git a/docs/source/markdown/podman-manifest.1.md b/docs/source/markdown/podman-manifest.1.md index c86035ce3..3353979ac 100644 --- a/docs/source/markdown/podman-manifest.1.md +++ b/docs/source/markdown/podman-manifest.1.md @@ -19,6 +19,8 @@ The `podman manifest` command provides subcommands which can be used to: | annotate | [podman-manifest-annotate(1)](podman-manifest-annotate.1.md) | Add or update information about an entry in a manifest list or image index. | | create | [podman-manifest-create(1)](podman-manifest-create.1.md) | Create a manifest list or image index. | | inspect | [podman-manifest-inspect(1)](podman-manifest-inspect.1.md) | Display a manifest list or image index. | +| push | [podman-manifest-push(1)](podman-manifest-push.1.md) | Push a manifest list or image index to a registry. | +| remove | [podman-manifest-remove(1)](podman-manifest-remove.1.md) | Remove an image from a manifest list or image index. | ## SEE ALSO -podman(1), podman-manifest-add(1), podman-manifest-annotate(1), podman-manifest-create(1), podman-manifest-inspect(1) +podman(1), podman-manifest-add(1), podman-manifest-annotate(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-manifest-push(1), podman-manifest-remove(1) diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index c46ba815a..cb822a70d 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -30,4 +30,6 @@ type ImageEngine interface { ManifestInspect(ctx context.Context, name string) ([]byte, error) ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error) ManifestAnnotate(ctx context.Context, names []string, opts ManifestAnnotateOptions) (string, error) + ManifestRemove(ctx context.Context, names []string) (string, error) + ManifestPush(ctx context.Context, names []string, manifestPushOpts ManifestPushOptions) error } diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go index d92b1dc9b..273052bb9 100644 --- a/pkg/domain/entities/manifest.go +++ b/pkg/domain/entities/manifest.go @@ -24,3 +24,8 @@ type ManifestAnnotateOptions struct { OSVersion string `json:"os_version" schema:"os_version"` Variant string `json:"variant" schema:"variant"` } + +type ManifestPushOptions struct { + Purge, Quiet, All, TlsVerify, RemoveSignatures bool + Authfile, CertDir, Creds, DigestFile, Format, SignBy string +} diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index 812507f0a..fca34dda2 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -6,15 +6,21 @@ import ( "context" "encoding/json" "fmt" + "io/ioutil" + "os" "strings" + "github.com/containers/buildah/manifests" buildahUtil "github.com/containers/buildah/util" + cp "github.com/containers/image/v5/copy" "github.com/containers/image/v5/docker" + "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/transports/alltransports" libpodImage "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/util" "github.com/opencontainers/go-digest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -137,3 +143,68 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt } return "", err } + +// ManifestRemove removes specified digest from the specified manifest list +func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) { + instanceDigest, err := digest.Parse(names[1]) + if err != nil { + return "", errors.Errorf(`invalid image digest "%s": %v`, names[1], err) + } + listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0]) + if err != nil { + return "", errors.Wrapf(err, "error retriving local image from image name %s", names[0]) + } + updatedListID, err := listImage.RemoveManifest(instanceDigest) + if err == nil { + return fmt.Sprintf("%s :%s\n", updatedListID, instanceDigest.String()), nil + } + return "", err +} + +// ManifestPush pushes a manifest list or image index to the destination +func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error { + listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0]) + if err != nil { + return errors.Wrapf(err, "error retriving local image from image name %s", names[0]) + } + dest, err := alltransports.ParseImageName(names[1]) + if err != nil { + return err + } + var manifestType string + if opts.Format != "" { + switch opts.Format { + case "oci": + manifestType = imgspecv1.MediaTypeImageManifest + case "v2s2", "docker": + manifestType = manifest.DockerV2Schema2MediaType + default: + return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci' or 'v2s2'", opts.Format) + } + } + options := manifests.PushOptions{ + Store: ir.Libpod.GetStore(), + SystemContext: ir.Libpod.SystemContext(), + ImageListSelection: cp.CopySpecificImages, + Instances: nil, + RemoveSignatures: opts.RemoveSignatures, + SignBy: opts.SignBy, + ManifestType: manifestType, + } + if opts.All { + options.ImageListSelection = cp.CopyAllImages + } + if !opts.Quiet { + options.ReportWriter = os.Stderr + } + digest, err := listImage.PushManifest(dest, options) + if err == nil && opts.Purge { + _, err = ir.Libpod.GetStore().DeleteImage(listImage.ID(), true) + } + if opts.DigestFile != "" { + if err = ioutil.WriteFile(opts.DigestFile, []byte(digest.String()), 0644); err != nil { + return buildahUtil.GetFailureCause(err, errors.Wrapf(err, "failed to write digest to file %q", opts.DigestFile)) + } + } + return err +} diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go index 3d3196019..7d9a0fce1 100644 --- a/pkg/domain/infra/tunnel/manifest.go +++ b/pkg/domain/infra/tunnel/manifest.go @@ -91,3 +91,18 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt } return fmt.Sprintf("%s :%s", updatedListID, names[1]), nil } + +// ManifestRemove removes the digest from manifest list +func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) { + updatedListID, err := manifests.Remove(ctx, names[0], names[1]) + if err != nil { + return updatedListID, errors.Wrapf(err, "error removing from manifest %s", names[0]) + } + return fmt.Sprintf("%s :%s\n", updatedListID, names[1]), nil +} + +// ManifestPush pushes a manifest list or image index to the destination +func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error { + _, err := manifests.Push(ctx, names[0], &names[1], &opts.All) + return err +} diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index be6919bdc..f622bf042 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -2,6 +2,8 @@ package integration import ( "os" + "path/filepath" + "strings" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" @@ -114,4 +116,90 @@ var _ = Describe("Podman manifest", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring(`"architecture": "bar"`)) }) + + It("podman manifest remove", func() { + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "inspect", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest)) + session = podmanTest.Podman([]string{"manifest", "remove", "foo", imageListARM64InstanceDigest}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "inspect", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(imageListAMD64InstanceDigest)) + Expect(session.OutputToString()).To(ContainSubstring(imageListARMInstanceDigest)) + Expect(session.OutputToString()).To(ContainSubstring(imageListPPC64LEInstanceDigest)) + Expect(session.OutputToString()).To(ContainSubstring(imageListS390XInstanceDigest)) + Expect(session.OutputToString()).To(Not(ContainSubstring(imageListARM64InstanceDigest))) + }) + + It("podman manifest remove not-found", func() { + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "add", "foo", imageList}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "remove", "foo", "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("podman manifest push", func() { + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "add", "--all", "foo", imageList}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + dest := filepath.Join(podmanTest.TempDir, "pushed") + err := os.MkdirAll(dest, os.ModePerm) + Expect(err).To(BeNil()) + defer func() { + os.RemoveAll(dest) + }() + session = podmanTest.Podman([]string{"manifest", "push", "--all", "foo", "dir:" + dest}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + files, err := filepath.Glob(dest + string(os.PathSeparator) + "*") + Expect(err).To(BeNil()) + check := SystemExec("sha256sum", files) + check.WaitWithDefaultTimeout() + Expect(check.ExitCode()).To(Equal(0)) + prefix := "sha256:" + Expect(check.OutputToString()).To(ContainSubstring(strings.TrimPrefix(imageListAMD64InstanceDigest, prefix))) + Expect(check.OutputToString()).To(ContainSubstring(strings.TrimPrefix(imageListARMInstanceDigest, prefix))) + Expect(check.OutputToString()).To(ContainSubstring(strings.TrimPrefix(imageListPPC64LEInstanceDigest, prefix))) + Expect(check.OutputToString()).To(ContainSubstring(strings.TrimPrefix(imageListS390XInstanceDigest, prefix))) + Expect(check.OutputToString()).To(ContainSubstring(strings.TrimPrefix(imageListARM64InstanceDigest, prefix))) + }) + + It("podman manifest push purge", func() { + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "add", "foo", imageList}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + dest := filepath.Join(podmanTest.TempDir, "pushed") + err := os.MkdirAll(dest, os.ModePerm) + Expect(err).To(BeNil()) + defer func() { + os.RemoveAll(dest) + }() + session = podmanTest.Podman([]string{"manifest", "push", "--purge", "foo", "dir:" + dest}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"manifest", "inspect", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) }) -- cgit v1.2.3-54-g00ecf