mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00
manifest create,add,inspect
Implememts manifest subcommands create, add, inspect. Signed-off-by: Qi Wang <qiwan@redhat.com>
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
||||
_ "github.com/containers/libpod/cmd/podman/containers"
|
||||
_ "github.com/containers/libpod/cmd/podman/healthcheck"
|
||||
_ "github.com/containers/libpod/cmd/podman/images"
|
||||
_ "github.com/containers/libpod/cmd/podman/manifest"
|
||||
_ "github.com/containers/libpod/cmd/podman/networks"
|
||||
_ "github.com/containers/libpod/cmd/podman/pods"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
|
49
cmd/podman/manifest/add.go
Normal file
49
cmd/podman/manifest/add.go
Normal file
@ -0,0 +1,49 @@
|
||||
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 (
|
||||
manifestAddOpts = entities.ManifestAddOptions{}
|
||||
addCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add images to a manifest list or image index",
|
||||
Long: "Adds an image to a manifest list or image index.",
|
||||
RunE: add,
|
||||
Example: `podman manifest add mylist:v1.11 image:v1.11-amd64
|
||||
podman manifest add mylist:v1.11 transport:imageName`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: addCmd,
|
||||
Parent: manifestCmd,
|
||||
})
|
||||
flags := addCmd.Flags()
|
||||
flags.BoolVar(&manifestAddOpts.All, "all", false, "add all of the list's images if the image is a list")
|
||||
flags.StringSliceVar(&manifestAddOpts.Annotation, "annotation", nil, "set an `annotation` for the specified image")
|
||||
flags.StringVar(&manifestAddOpts.Arch, "arch", "", "override the `architecture` of the specified image")
|
||||
flags.StringSliceVar(&manifestAddOpts.Features, "features", nil, "override the `features` of the specified image")
|
||||
flags.StringVar(&manifestAddOpts.OSVersion, "os-version", "", "override the OS `version` of the specified image")
|
||||
flags.StringVar(&manifestAddOpts.Variant, "variant", "", "override the `Variant` of the specified image")
|
||||
}
|
||||
|
||||
func add(cmd *cobra.Command, args []string) error {
|
||||
manifestAddOpts.Images = []string{args[1], args[0]}
|
||||
listID, err := registry.ImageEngine().ManifestAdd(context.Background(), manifestAddOpts)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error adding to manifest list %s", args[0])
|
||||
}
|
||||
fmt.Printf("%s\n", listID)
|
||||
return nil
|
||||
}
|
44
cmd/podman/manifest/create.go
Normal file
44
cmd/podman/manifest/create.go
Normal file
@ -0,0 +1,44 @@
|
||||
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 (
|
||||
manifestCreateOpts = entities.ManifestCreateOptions{}
|
||||
createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create manifest list or image index",
|
||||
Long: "Creates manifest lists or image indexes.",
|
||||
RunE: create,
|
||||
Example: `podman manifest create mylist:v1.11
|
||||
podman manifest create mylist:v1.11 arch-specific-image-to-add
|
||||
podman manifest create --all mylist:v1.11 transport:tagged-image-to-add`,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: createCmd,
|
||||
Parent: manifestCmd,
|
||||
})
|
||||
flags := createCmd.Flags()
|
||||
flags.BoolVar(&manifestCreateOpts.All, "all", false, "add all of the lists' images if the images to add are lists")
|
||||
}
|
||||
|
||||
func create(cmd *cobra.Command, args []string) error {
|
||||
imageID, err := registry.ImageEngine().ManifestCreate(context.Background(), args[:1], args[1:], manifestCreateOpts)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating manifest %s", args[0])
|
||||
}
|
||||
fmt.Printf("%s\n", imageID)
|
||||
return nil
|
||||
}
|
39
cmd/podman/manifest/inspect.go
Normal file
39
cmd/podman/manifest/inspect.go
Normal file
@ -0,0 +1,39 @@
|
||||
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 (
|
||||
inspectCmd = &cobra.Command{
|
||||
Use: "inspect IMAGE",
|
||||
Short: "Display the contents of a manifest list or image index",
|
||||
Long: "Display the contents of a manifest list or image index.",
|
||||
RunE: inspect,
|
||||
Example: "podman manifest inspect localhost/list",
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: inspectCmd,
|
||||
Parent: manifestCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func inspect(cmd *cobra.Command, args []string) error {
|
||||
buf, err := registry.ImageEngine().ManifestInspect(context.Background(), args[0])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error inspect manifest %s", args[0])
|
||||
}
|
||||
fmt.Printf("%s\n", buf)
|
||||
return nil
|
||||
}
|
27
cmd/podman/manifest/manifest.go
Normal file
27
cmd/podman/manifest/manifest.go
Normal file
@ -0,0 +1,27 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
manifestDescription = "Creates, modifies, and pushes manifest lists and image indexes."
|
||||
manifestCmd = &cobra.Command{
|
||||
Use: "manifest",
|
||||
Short: "Manipulate manifest lists and image indexes",
|
||||
Long: manifestDescription,
|
||||
TraverseChildren: true,
|
||||
RunE: registry.SubCommandExists,
|
||||
Example: `podman manifest create localhost/list
|
||||
podman manifest inspect localhost/list`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: manifestCmd,
|
||||
})
|
||||
}
|
@ -1733,6 +1733,83 @@ _podman_logs() {
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_manifest() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
subcommands="
|
||||
add
|
||||
create
|
||||
inspect
|
||||
"
|
||||
__podman_subcommands "$subcommands" && return
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_manifest_add() {
|
||||
local options_with_args="
|
||||
--annotation
|
||||
--arch
|
||||
--features
|
||||
--os-version
|
||||
--variant
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
--all
|
||||
--help
|
||||
-h
|
||||
"
|
||||
|
||||
_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_create() {
|
||||
local boolean_options="
|
||||
--all
|
||||
--help
|
||||
-h
|
||||
"
|
||||
|
||||
_complete_ "$boolean_options"
|
||||
}
|
||||
|
||||
_podman_manifest_inspect() {
|
||||
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
|
||||
@ -3356,6 +3433,7 @@ _podman_podman() {
|
||||
login
|
||||
logout
|
||||
logs
|
||||
manifest
|
||||
mount
|
||||
pause
|
||||
pod
|
||||
|
69
docs/source/markdown/podman-manifest-add.1.md
Normal file
69
docs/source/markdown/podman-manifest-add.1.md
Normal file
@ -0,0 +1,69 @@
|
||||
% podman-manifest-add(1)
|
||||
|
||||
## NAME
|
||||
podman\-manifest\-add - Add an image to a manifest list or image index
|
||||
|
||||
## SYNOPSIS
|
||||
**podman manifest add** *listnameorindexname* *imagename*
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Adds the specified image to the specified manifest list or image index.
|
||||
|
||||
## RETURN VALUE
|
||||
The list image's ID.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--all**
|
||||
|
||||
If the image which should be added to the list or index is itself a list or
|
||||
index, add all of the contents to the local list. By default, only one image
|
||||
from such a list or index will be added to the list or index. Combining
|
||||
*--all* with any of the other options described below is NOT recommended.
|
||||
|
||||
**--annotation** *annotation=value*
|
||||
|
||||
Set an annotation on the entry for the newly-added image.
|
||||
|
||||
**--arch**
|
||||
|
||||
Override the architecture which the list or index records as a requirement for
|
||||
the image. If *imageName* refers to a manifest list or image index, the
|
||||
architecture information will be retrieved from it. Otherwise, it will be
|
||||
retrieved from the image's configuration information.
|
||||
|
||||
**--features**
|
||||
|
||||
Specify the features list which the list or index records as requirements for
|
||||
the image. This option is rarely used.
|
||||
|
||||
**--os-version**
|
||||
|
||||
Specify the OS version which the list or index records as a requirement for the
|
||||
image. This option is rarely used.
|
||||
|
||||
**--variant**
|
||||
|
||||
Specify the variant which the list or index records for the image. This option
|
||||
is typically used to distinguish between multiple entries which share the same
|
||||
architecture value, but which expect different versions of its instruction set.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
```
|
||||
podman manifest add mylist:v1.11 docker://fedora
|
||||
71c201d10fffdcac52968a000d85a0a016ca1c7d5473948000d3131c1773d965
|
||||
```
|
||||
|
||||
```
|
||||
podman manifest add --all mylist:v1.11 docker://fedora
|
||||
71c201d10fffdcac52968a000d85a0a016ca1c7d5473948000d3131c1773d965
|
||||
```
|
||||
|
||||
```
|
||||
podman manifest add --arch arm64 --variant v8 mylist:v1.11 docker://71c201d10fffdcac52968a000d85a0a016ca1c7d5473948000d3131c1773d965
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-rmi(1)
|
43
docs/source/markdown/podman-manifest-create.1.md
Normal file
43
docs/source/markdown/podman-manifest-create.1.md
Normal file
@ -0,0 +1,43 @@
|
||||
% podman-manifest-create(1)
|
||||
|
||||
## NAME
|
||||
podman\-manifest\-create - Create a manifest list or image index
|
||||
|
||||
## SYNOPSIS
|
||||
**podman manifest create** [*options*] *listnameorindexname* [*imagename* ...]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Creates a new manifest list and stores it as an image in local storage using
|
||||
the specified name.
|
||||
|
||||
If additional images are specified, they are added to the newly-created list or
|
||||
index.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--all**
|
||||
|
||||
If any of the images which should be added to the new list or index are
|
||||
themselves lists or indexes, add all of their contents. By default, only one
|
||||
image from such a list will be added to the newly-created list or index.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
```
|
||||
podman manifest create mylist:v1.11
|
||||
9cfd24048d5fc80903f088f1531a21bff01172abe66effa8941a4c2308dc745f
|
||||
```
|
||||
|
||||
```
|
||||
podman manifest create mylist:v1.11 docker://fedora
|
||||
5c2bc76bfb4ba6665a7973f7e1c05ee0536b4580637f27adc9fa5a4b2bc03cf1
|
||||
```
|
||||
|
||||
```
|
||||
podman manifest create --all mylist:v1.11 docker://fedora
|
||||
30330571e79c65288a4fca421d9aed29b0210d57294d9c2056743fdcf6e3967b
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-manifest(1), podman-manifest-add(1), podman-manifest-inspect(1), podman-rmi(1)
|
24
docs/source/markdown/podman-manifest-inspect.1.md
Normal file
24
docs/source/markdown/podman-manifest-inspect.1.md
Normal file
@ -0,0 +1,24 @@
|
||||
% podman-manifest-inspect(1)
|
||||
|
||||
## NAME
|
||||
podman\-manifest\-inspect - Display a manifest list or image index
|
||||
|
||||
## SYNOPSIS
|
||||
**podman manifest inspect** *listnameorindexname*
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Displays the manifest list or image index stored using the specified image name.
|
||||
|
||||
## RETURN VALUE
|
||||
|
||||
A formatted JSON representation of the manifest list or image index.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
```
|
||||
podman manifest inspect mylist:v1.11
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-manifest(1), podman-manifest-create(1), podman-manifest-add(1), podman-rmi(1)
|
23
docs/source/markdown/podman-manifest.1.md
Normal file
23
docs/source/markdown/podman-manifest.1.md
Normal file
@ -0,0 +1,23 @@
|
||||
% podman-manifest(1)
|
||||
|
||||
## NAME
|
||||
podman\-manifest - Create and manipulate manifest lists and image indexes
|
||||
|
||||
## SYNOPSIS
|
||||
**podman manifest** *subcommand*
|
||||
|
||||
## DESCRIPTION
|
||||
The `podman manifest` command provides subcommands which can be used to:
|
||||
|
||||
* Create a working Docker manifest list or OCI image index.
|
||||
|
||||
## SUBCOMMANDS
|
||||
|
||||
| Command | Man Page | Description |
|
||||
| ------- | ---------------------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| add | [podman-manifest-add(1)](podman-manifest-add.1.md) | Add an image to 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. |
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-manifest-add(1), podman-manifest-create(1), podman-manifest-inspect(1)
|
@ -169,6 +169,7 @@ the exit codes follow the `chroot` standard, see below:
|
||||
| [podman-login(1)](podman-login.1.md) | Login to a container registry. |
|
||||
| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. |
|
||||
| [podman-logs(1)](podman-logs.1.md) | Display the logs of one or more containers. |
|
||||
| [podman-manifest(1)](podman-manifest.1.md) | Create and manipulate manifest lists and image indexes. |
|
||||
| [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. |
|
||||
| [podman-network(1)](podman-network.1.md) | Manage Podman CNI networks. |
|
||||
| [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
|
||||
|
1
go.sum
1
go.sum
@ -131,6 +131,7 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
|
@ -733,6 +733,11 @@ func (r *Runtime) StorageConfig() storage.StoreOptions {
|
||||
return r.storageConfig
|
||||
}
|
||||
|
||||
// GetStore returns the runtime stores
|
||||
func (r *Runtime) GetStore() storage.Store {
|
||||
return r.store
|
||||
}
|
||||
|
||||
// DBConfig is a set of Libpod runtime configuration settings that are saved in
|
||||
// a State when it is first created, and can subsequently be retrieved.
|
||||
type DBConfig struct {
|
||||
|
@ -25,4 +25,7 @@ type ImageEngine interface {
|
||||
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
|
||||
Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
|
||||
Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
|
||||
ManifestCreate(ctx context.Context, names, images []string, opts ManifestCreateOptions) (string, error)
|
||||
ManifestInspect(ctx context.Context, name string) ([]byte, error)
|
||||
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
|
||||
}
|
||||
|
15
pkg/domain/entities/manifest.go
Normal file
15
pkg/domain/entities/manifest.go
Normal file
@ -0,0 +1,15 @@
|
||||
package entities
|
||||
|
||||
type ManifestCreateOptions struct {
|
||||
All bool `schema:"all"`
|
||||
}
|
||||
|
||||
type ManifestAddOptions struct {
|
||||
All bool `json:"all" schema:"all"`
|
||||
Annotation []string `json:"annotation" schema:"annotation"`
|
||||
Arch string `json:"arch" schema:"arch"`
|
||||
Features []string `json:"features" schema:"features"`
|
||||
Images []string `json:"images" schema:"images"`
|
||||
OSVersion string `json:"os_version" schema:"os_version"`
|
||||
Variant string `json:"variant" schema:"variant"`
|
||||
}
|
101
pkg/domain/infra/abi/manifest.go
Normal file
101
pkg/domain/infra/abi/manifest.go
Normal file
@ -0,0 +1,101 @@
|
||||
// +build ABISupport
|
||||
|
||||
package abi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
buildahUtil "github.com/containers/buildah/util"
|
||||
"github.com/containers/image/v5/docker"
|
||||
"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/pkg/errors"
|
||||
)
|
||||
|
||||
// ManifestCreate implements logic for creating manifest lists via ImageEngine
|
||||
func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
|
||||
fullNames, err := buildahUtil.ExpandNames(names, "", ir.Libpod.SystemContext(), ir.Libpod.GetStore())
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error encountered while expanding image name %q", names)
|
||||
}
|
||||
imageID, err := libpodImage.CreateManifestList(ir.Libpod.ImageRuntime(), *ir.Libpod.SystemContext(), fullNames, images, opts.All)
|
||||
if err != nil {
|
||||
return imageID, err
|
||||
}
|
||||
return imageID, err
|
||||
}
|
||||
|
||||
// ManifestInspect returns the content of a manifest list or image
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
|
||||
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
|
||||
_, err := alltransports.ParseImageName(name)
|
||||
if err != nil {
|
||||
_, err = alltransports.ParseImageName(dockerPrefix + name)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid image reference %q", name)
|
||||
}
|
||||
}
|
||||
image, err := ir.Libpod.ImageRuntime().New(ctx, name, "", "", nil, nil, libpodImage.SigningOptions{}, nil, util.PullImageMissing)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "reading image %q", name)
|
||||
}
|
||||
|
||||
list, err := image.InspectManifest()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "loading manifest %q", name)
|
||||
}
|
||||
buf, err := json.MarshalIndent(list, "", " ")
|
||||
if err != nil {
|
||||
return buf, errors.Wrapf(err, "error rendering manifest for display")
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// ManifestAdd adds images to the manifest list
|
||||
func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAddOptions) (string, error) {
|
||||
imageSpec := opts.Images[0]
|
||||
listImageSpec := opts.Images[1]
|
||||
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
|
||||
_, err := alltransports.ParseImageName(imageSpec)
|
||||
if err != nil {
|
||||
_, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, imageSpec))
|
||||
if err != nil {
|
||||
return "", errors.Errorf("invalid image reference %q", imageSpec)
|
||||
}
|
||||
}
|
||||
listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(listImageSpec)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error retriving local image from image name %s", listImageSpec)
|
||||
}
|
||||
|
||||
manifestAddOpts := libpodImage.ManifestAddOpts{
|
||||
All: opts.All,
|
||||
Arch: opts.Arch,
|
||||
Features: opts.Features,
|
||||
Images: opts.Images,
|
||||
OSVersion: opts.OSVersion,
|
||||
Variant: opts.Variant,
|
||||
}
|
||||
if len(opts.Annotation) != 0 {
|
||||
annotations := make(map[string]string)
|
||||
for _, annotationSpec := range opts.Annotation {
|
||||
spec := strings.SplitN(annotationSpec, "=", 2)
|
||||
if len(spec) != 2 {
|
||||
return "", errors.Errorf("no value given for annotation %q", spec[0])
|
||||
}
|
||||
annotations[spec[0]] = spec[1]
|
||||
}
|
||||
manifestAddOpts.Annotation = annotations
|
||||
}
|
||||
listID, err := listImage.AddManifest(*ir.Libpod.SystemContext(), manifestAddOpts)
|
||||
if err != nil {
|
||||
return listID, err
|
||||
}
|
||||
return listID, nil
|
||||
}
|
63
pkg/domain/infra/tunnel/manifest.go
Normal file
63
pkg/domain/infra/tunnel/manifest.go
Normal file
@ -0,0 +1,63 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/libpod/pkg/bindings/manifests"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ManifestCreate implements manifest create via ImageEngine
|
||||
func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
|
||||
imageID, err := manifests.Create(ir.ClientCxt, names, images, &opts.All)
|
||||
if err != nil {
|
||||
return imageID, errors.Wrapf(err, "error creating manifest")
|
||||
}
|
||||
return imageID, err
|
||||
}
|
||||
|
||||
// ManifestInspect returns contents of manifest list with given name
|
||||
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
|
||||
list, err := manifests.Inspect(ir.ClientCxt, name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting content of manifest list or image %s", name)
|
||||
}
|
||||
|
||||
buf, err := json.MarshalIndent(list, "", " ")
|
||||
if err != nil {
|
||||
return buf, errors.Wrapf(err, "error rendering manifest for display")
|
||||
}
|
||||
return buf, err
|
||||
}
|
||||
|
||||
// ManifestAdd adds images to the manifest list
|
||||
func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAddOptions) (string, error) {
|
||||
manifestAddOpts := image.ManifestAddOpts{
|
||||
All: opts.All,
|
||||
Arch: opts.Arch,
|
||||
Features: opts.Features,
|
||||
Images: opts.Images,
|
||||
OSVersion: opts.OSVersion,
|
||||
Variant: opts.Variant,
|
||||
}
|
||||
if len(opts.Annotation) != 0 {
|
||||
annotations := make(map[string]string)
|
||||
for _, annotationSpec := range opts.Annotation {
|
||||
spec := strings.SplitN(annotationSpec, "=", 2)
|
||||
if len(spec) != 2 {
|
||||
return "", errors.Errorf("no value given for annotation %q", spec[0])
|
||||
}
|
||||
annotations[spec[0]] = spec[1]
|
||||
}
|
||||
manifestAddOpts.Annotation = annotations
|
||||
}
|
||||
listID, err := manifests.Add(ctx, opts.Images[1], manifestAddOpts)
|
||||
if err != nil {
|
||||
return listID, errors.Wrapf(err, "error adding to manifest list %s", opts.Images[1])
|
||||
}
|
||||
return listID, nil
|
||||
}
|
88
test/e2e/manifest_test.go
Normal file
88
test/e2e/manifest_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/containers/libpod/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman manifest", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest *PodmanTestIntegration
|
||||
)
|
||||
|
||||
const (
|
||||
imageList = "docker://k8s.gcr.io/pause:3.1"
|
||||
imageListInstance = "docker://k8s.gcr.io/pause@sha256:f365626a556e58189fc21d099fc64603db0f440bff07f77c740989515c544a39"
|
||||
imageListARM64InstanceDigest = "sha256:f365626a556e58189fc21d099fc64603db0f440bff07f77c740989515c544a39"
|
||||
imageListAMD64InstanceDigest = "sha256:59eec8837a4d942cc19a52b8c09ea75121acc38114a2c68b98983ce9356b8610"
|
||||
imageListARMInstanceDigest = "sha256:c84b0a3a07b628bc4d62e5047d0f8dff80f7c00979e1e28a821a033ecda8fe53"
|
||||
imageListPPC64LEInstanceDigest = "sha256:bcf9771c0b505e68c65440474179592ffdfa98790eb54ffbf129969c5e429990"
|
||||
imageListS390XInstanceDigest = "sha256:882a20ee0df7399a445285361d38b711c299ca093af978217112c73803546d5e"
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanTestCreate(tempdir)
|
||||
podmanTest.Setup()
|
||||
podmanTest.SeedImages()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.Cleanup()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
processTestResult(f)
|
||||
|
||||
})
|
||||
It("podman manifest create", func() {
|
||||
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman manifest add", func() {
|
||||
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
session = podmanTest.Podman([]string{"manifest", "add", "--arch=arm64", "foo", imageListInstance})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman manifest add one", func() {
|
||||
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
session = podmanTest.Podman([]string{"manifest", "add", "--arch=arm64", "foo", imageListInstance})
|
||||
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))
|
||||
})
|
||||
|
||||
It("podman manifest add --all", 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(imageListAMD64InstanceDigest))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imageListARMInstanceDigest))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imageListPPC64LEInstanceDigest))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imageListS390XInstanceDigest))
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user