Manifest remove, push
Implements podman manifest remove and podman manifest push. Signed-off-by: Qi Wang <qiwan@redhat.com>
This commit is contained in:
parent
0eb905ff2c
commit
5621f5199d
|
|
@ -18,7 +18,9 @@ var (
|
||||||
Example: `podman manifest add mylist:v1.11 image:v1.11-amd64
|
Example: `podman manifest add mylist:v1.11 image:v1.11-amd64
|
||||||
podman manifest create localhost/list
|
podman manifest create localhost/list
|
||||||
podman manifest inspect 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`,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -1742,7 +1742,9 @@ _podman_manifest() {
|
||||||
add
|
add
|
||||||
create
|
create
|
||||||
inspect
|
inspect
|
||||||
"
|
push
|
||||||
|
remove
|
||||||
|
"
|
||||||
__podman_subcommands "$subcommands" && return
|
__podman_subcommands "$subcommands" && return
|
||||||
|
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
|
|
@ -1838,6 +1840,57 @@ _podman_manifest_inspect() {
|
||||||
esac
|
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() {
|
_podman_pull() {
|
||||||
local options_with_args="
|
local options_with_args="
|
||||||
--authfile
|
--authfile
|
||||||
|
|
|
||||||
|
|
@ -73,4 +73,4 @@ podman manifest add --arch arm64 --variant v8 mylist:v1.11 docker://71c201d10fff
|
||||||
```
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## 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)
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,4 @@ podman manifest create --all mylist:v1.11 docker://fedora
|
||||||
```
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## 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)
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,4 @@ podman manifest inspect mylist:v1.11
|
||||||
```
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## 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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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. |
|
| 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. |
|
| 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. |
|
| 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
|
## 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)
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,6 @@ type ImageEngine interface {
|
||||||
ManifestInspect(ctx context.Context, name string) ([]byte, error)
|
ManifestInspect(ctx context.Context, name string) ([]byte, error)
|
||||||
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
|
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
|
||||||
ManifestAnnotate(ctx context.Context, names []string, opts ManifestAnnotateOptions) (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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,8 @@ type ManifestAnnotateOptions struct {
|
||||||
OSVersion string `json:"os_version" schema:"os_version"`
|
OSVersion string `json:"os_version" schema:"os_version"`
|
||||||
Variant string `json:"variant" schema:"variant"`
|
Variant string `json:"variant" schema:"variant"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ManifestPushOptions struct {
|
||||||
|
Purge, Quiet, All, TlsVerify, RemoveSignatures bool
|
||||||
|
Authfile, CertDir, Creds, DigestFile, Format, SignBy string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,21 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/buildah/manifests"
|
||||||
buildahUtil "github.com/containers/buildah/util"
|
buildahUtil "github.com/containers/buildah/util"
|
||||||
|
cp "github.com/containers/image/v5/copy"
|
||||||
"github.com/containers/image/v5/docker"
|
"github.com/containers/image/v5/docker"
|
||||||
|
"github.com/containers/image/v5/manifest"
|
||||||
"github.com/containers/image/v5/transports/alltransports"
|
"github.com/containers/image/v5/transports/alltransports"
|
||||||
libpodImage "github.com/containers/libpod/libpod/image"
|
libpodImage "github.com/containers/libpod/libpod/image"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
@ -137,3 +143,68 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
|
||||||
}
|
}
|
||||||
return "", err
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,3 +91,18 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s :%s", updatedListID, names[1]), nil
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
. "github.com/containers/libpod/test/utils"
|
. "github.com/containers/libpod/test/utils"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
|
|
@ -114,4 +116,90 @@ var _ = Describe("Podman manifest", func() {
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
Expect(session.OutputToString()).To(ContainSubstring(`"architecture": "bar"`))
|
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)))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue