mirror of https://github.com/containers/podman.git
Merge pull request #10836 from Luap99/diff
podman diff accept two images or containers
This commit is contained in:
commit
895b815188
|
|
@ -1,10 +1,11 @@
|
|||
package containers
|
||||
|
||||
import (
|
||||
"github.com/containers/common/pkg/report"
|
||||
"github.com/containers/podman/v3/cmd/podman/common"
|
||||
"github.com/containers/podman/v3/cmd/podman/diff"
|
||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||
"github.com/containers/podman/v3/cmd/podman/validate"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -13,11 +14,11 @@ import (
|
|||
var (
|
||||
// podman container _diff_
|
||||
diffCmd = &cobra.Command{
|
||||
Use: "diff [options] CONTAINER",
|
||||
Args: validate.IDOrLatestArgs,
|
||||
Use: "diff [options] CONTAINER [CONTAINER]",
|
||||
Args: diff.ValidateContainerDiffArgs,
|
||||
Short: "Inspect changes to the container's file systems",
|
||||
Long: `Displays changes to the container filesystem's'. The container will be compared to its parent layer.`,
|
||||
RunE: diff,
|
||||
Long: `Displays changes to the container filesystem's'. The container will be compared to its parent layer or the second argument when given.`,
|
||||
RunE: diffRun,
|
||||
ValidArgsFunction: common.AutocompleteContainers,
|
||||
Example: `podman container diff myCtr
|
||||
podman container diff -l --format json myCtr`,
|
||||
|
|
@ -33,41 +34,22 @@ func init() {
|
|||
|
||||
diffOpts = &entities.DiffOptions{}
|
||||
flags := diffCmd.Flags()
|
||||
|
||||
// FIXME: Why does this exists? It is not used anywhere.
|
||||
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
|
||||
_ = flags.MarkHidden("archive")
|
||||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
|
||||
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
|
||||
|
||||
validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
|
||||
}
|
||||
|
||||
func diff(cmd *cobra.Command, args []string) error {
|
||||
func diffRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 && !diffOpts.Latest {
|
||||
return errors.New("container must be specified: podman container diff [options [...]] ID-NAME")
|
||||
}
|
||||
|
||||
var id string
|
||||
if len(args) > 0 {
|
||||
id = args[0]
|
||||
}
|
||||
results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), id, *diffOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case report.IsJSON(diffOpts.Format):
|
||||
return common.ChangesToJSON(results)
|
||||
case diffOpts.Format == "":
|
||||
return common.ChangesToTable(results)
|
||||
default:
|
||||
return errors.New("only supported value for '--format' is 'json'")
|
||||
}
|
||||
}
|
||||
|
||||
func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
|
||||
diffOpts = &options
|
||||
return diff(cmd, args)
|
||||
diffOpts.Type = define.DiffContainer
|
||||
return diff.Diff(cmd, args, *diffOpts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/podman/v3/cmd/podman/common"
|
||||
"github.com/containers/podman/v3/cmd/podman/containers"
|
||||
"github.com/containers/podman/v3/cmd/podman/images"
|
||||
"github.com/containers/podman/v3/cmd/podman/diff"
|
||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||
"github.com/containers/podman/v3/cmd/podman/validate"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -16,13 +14,13 @@ import (
|
|||
|
||||
var (
|
||||
// Command: podman _diff_ Object_ID
|
||||
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`
|
||||
diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer or the second argument when given.`
|
||||
diffCmd = &cobra.Command{
|
||||
Use: "diff [options] {CONTAINER|IMAGE}",
|
||||
Args: validate.IDOrLatestArgs,
|
||||
Use: "diff [options] {CONTAINER|IMAGE} [{CONTAINER|IMAGE}]",
|
||||
Args: diff.ValidateContainerDiffArgs,
|
||||
Short: "Display the changes to the object's file system",
|
||||
Long: diffDescription,
|
||||
RunE: diff,
|
||||
RunE: diffRun,
|
||||
ValidArgsFunction: common.AutocompleteContainersAndImages,
|
||||
Example: `podman diff imageID
|
||||
podman diff ctrID
|
||||
|
|
@ -37,36 +35,18 @@ func init() {
|
|||
Command: diffCmd,
|
||||
})
|
||||
flags := diffCmd.Flags()
|
||||
// FIXME: Why does this exists? It is not used anywhere.
|
||||
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
|
||||
_ = flags.MarkHidden("archive")
|
||||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
|
||||
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
|
||||
|
||||
validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
|
||||
}
|
||||
|
||||
func diff(cmd *cobra.Command, args []string) error {
|
||||
// Latest implies looking for a container
|
||||
if diffOpts.Latest {
|
||||
return containers.Diff(cmd, args, diffOpts)
|
||||
}
|
||||
|
||||
options := entities.ContainerExistsOptions{
|
||||
External: true,
|
||||
}
|
||||
if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0], options); err != nil {
|
||||
return err
|
||||
} else if found.Value {
|
||||
return containers.Diff(cmd, args, diffOpts)
|
||||
}
|
||||
|
||||
if found, err := registry.ImageEngine().Exists(registry.GetContext(), args[0]); err != nil {
|
||||
return err
|
||||
} else if found.Value {
|
||||
return images.Diff(cmd, args, diffOpts)
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s not found on system", args[0])
|
||||
func diffRun(cmd *cobra.Command, args []string) error {
|
||||
diffOpts.Type = define.DiffAll
|
||||
return diff.Diff(cmd, args, diffOpts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
package diff
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/common/pkg/report"
|
||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
|
||||
results, err := registry.ContainerEngine().Diff(registry.GetContext(), args, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case report.IsJSON(options.Format):
|
||||
return changesToJSON(results)
|
||||
case options.Format == "":
|
||||
return changesToTable(results)
|
||||
default:
|
||||
return errors.New("only supported value for '--format' is 'json'")
|
||||
}
|
||||
}
|
||||
|
||||
type ChangesReportJSON struct {
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Added []string `json:"added,omitempty"`
|
||||
Deleted []string `json:"deleted,omitempty"`
|
||||
}
|
||||
|
||||
func changesToJSON(diffs *entities.DiffReport) error {
|
||||
body := ChangesReportJSON{}
|
||||
for _, row := range diffs.Changes {
|
||||
switch row.Kind {
|
||||
case archive.ChangeAdd:
|
||||
body.Added = append(body.Added, row.Path)
|
||||
case archive.ChangeDelete:
|
||||
body.Deleted = append(body.Deleted, row.Path)
|
||||
case archive.ChangeModify:
|
||||
body.Changed = append(body.Changed, row.Path)
|
||||
default:
|
||||
return errors.Errorf("output kind %q not recognized", row.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
// Pull in configured json library
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(body)
|
||||
}
|
||||
|
||||
func changesToTable(diffs *entities.DiffReport) error {
|
||||
for _, row := range diffs.Changes {
|
||||
fmt.Fprintln(os.Stdout, row.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
|
||||
func ValidateContainerDiffArgs(cmd *cobra.Command, args []string) error {
|
||||
given, _ := cmd.Flags().GetBool("latest")
|
||||
if len(args) > 0 && !given {
|
||||
return cobra.RangeArgs(1, 2)(cmd, args)
|
||||
}
|
||||
if len(args) > 0 && given {
|
||||
return errors.New("--latest and containers cannot be used together")
|
||||
}
|
||||
if len(args) == 0 && !given {
|
||||
return errors.Errorf("%q requires a name, id, or the \"--latest\" flag", cmd.CommandPath())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/common/pkg/report"
|
||||
"github.com/containers/podman/v3/cmd/podman/common"
|
||||
"github.com/containers/podman/v3/cmd/podman/diff"
|
||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
|
@ -13,11 +13,11 @@ import (
|
|||
var (
|
||||
// podman container _inspect_
|
||||
diffCmd = &cobra.Command{
|
||||
Use: "diff [options] IMAGE",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "diff [options] IMAGE [IMAGE]",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Short: "Inspect changes to the image's file systems",
|
||||
Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer.`,
|
||||
RunE: diff,
|
||||
Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer or the second argument when given.`,
|
||||
RunE: diffRun,
|
||||
ValidArgsFunction: common.AutocompleteImages,
|
||||
Example: `podman image diff myImage
|
||||
podman image diff --format json redis:alpine`,
|
||||
|
|
@ -39,31 +39,11 @@ func diffFlags(flags *pflag.FlagSet) {
|
|||
_ = flags.MarkDeprecated("archive", "Provided for backwards compatibility, has no impact on output.")
|
||||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
|
||||
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
|
||||
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
|
||||
}
|
||||
|
||||
func diff(cmd *cobra.Command, args []string) error {
|
||||
if diffOpts.Latest {
|
||||
return errors.New("image diff does not support --latest")
|
||||
}
|
||||
|
||||
results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], *diffOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case report.IsJSON(diffOpts.Format):
|
||||
return common.ChangesToJSON(results)
|
||||
case diffOpts.Format == "":
|
||||
return common.ChangesToTable(results)
|
||||
default:
|
||||
return errors.New("only supported value for '--format' is 'json'")
|
||||
}
|
||||
}
|
||||
|
||||
func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
|
||||
diffOpts = &options
|
||||
return diff(cmd, args)
|
||||
func diffRun(cmd *cobra.Command, args []string) error {
|
||||
diffOpts.Type = define.DiffImage
|
||||
return diff.Diff(cmd, args, *diffOpts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
.so man1/podman-diff.1
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
% podman-container-diff(1)
|
||||
|
||||
## NAME
|
||||
podman\-container\-diff - Inspect changes on a container's filesystem
|
||||
|
||||
## SYNOPSIS
|
||||
**podman container diff** [*options*] *container* [*container*]
|
||||
|
||||
## DESCRIPTION
|
||||
Displays changes on a container's filesystem. The container will be compared to its parent layer or the second argument when given.
|
||||
|
||||
The output is prefixed with the following symbols:
|
||||
|
||||
| Symbol | Description |
|
||||
|--------|-------------|
|
||||
| A | A file or directory was added. |
|
||||
| D | A file or directory was deleted. |
|
||||
| C | A file or directory was changed. |
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--format**
|
||||
|
||||
Alter the output into a different format. The only valid format for **podman container diff** is `json`.
|
||||
|
||||
#### **--latest**, **-l**
|
||||
|
||||
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
|
||||
to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client)
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
```
|
||||
# podman container diff container1
|
||||
C /usr
|
||||
C /usr/local
|
||||
C /usr/local/bin
|
||||
A /usr/local/bin/docker-entrypoint.sh
|
||||
```
|
||||
|
||||
```
|
||||
$ podman container diff --format json container1 container2
|
||||
{
|
||||
"added": [
|
||||
"/test"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
**[podman(1)](podman.1.md)**, **[podman-container(1)](podman-container.1.md)**
|
||||
|
||||
## HISTORY
|
||||
July 2021, Originally compiled by Paul Holzinger <pholzing@redhat.com>
|
||||
|
|
@ -19,7 +19,7 @@ The container command allows you to manage containers
|
|||
| commit | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. |
|
||||
| cp | [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. |
|
||||
| create | [podman-create(1)](podman-create.1.md) | Create a new container. |
|
||||
| diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. |
|
||||
| diff | [podman-container-diff(1)](podman-container-diff.1.md) | Inspect changes on a container's filesystem |
|
||||
| exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. |
|
||||
| exists | [podman-container-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage |
|
||||
| export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. |
|
||||
|
|
|
|||
|
|
@ -4,18 +4,24 @@
|
|||
podman\-diff - Inspect changes on a container or image's filesystem
|
||||
|
||||
## SYNOPSIS
|
||||
**podman diff** [*options*] *name*
|
||||
|
||||
**podman container diff** [*options*] *name*
|
||||
**podman diff** [*options*] *container|image* [*container|image*]
|
||||
|
||||
## DESCRIPTION
|
||||
Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer
|
||||
Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer or the second argument when given.
|
||||
|
||||
The output is prefixed with the following symbols:
|
||||
|
||||
| Symbol | Description |
|
||||
|--------|-------------|
|
||||
| A | A file or directory was added. |
|
||||
| D | A file or directory was deleted. |
|
||||
| C | A file or directory was changed. |
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--format**
|
||||
|
||||
Alter the output into a different format. The only valid format for diff is `json`.
|
||||
Alter the output into a different format. The only valid format for **podman diff** is `json`.
|
||||
|
||||
#### **--latest**, **-l**
|
||||
|
||||
|
|
@ -25,15 +31,12 @@ to run containers such as CRI-O, the last started container could be from either
|
|||
## EXAMPLE
|
||||
|
||||
```
|
||||
# podman diff redis:alpine
|
||||
C /usr
|
||||
C /usr/local
|
||||
C /usr/local/bin
|
||||
A /usr/local/bin/docker-entrypoint.sh
|
||||
$ podman diff container1
|
||||
A /myscript.sh
|
||||
```
|
||||
|
||||
```
|
||||
# podman diff --format json redis:alpine
|
||||
$ podman diff --format json myimage
|
||||
{
|
||||
"changed": [
|
||||
"/usr",
|
||||
|
|
@ -46,8 +49,13 @@ A /usr/local/bin/docker-entrypoint.sh
|
|||
}
|
||||
```
|
||||
|
||||
```
|
||||
$ podman diff container1 image1
|
||||
A /test
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1)
|
||||
**[podman(1)](podman.1.md)**, **[podman-container-diff(1)](podman-container-diff.1.md)**, **[podman-image-diff(1)](podman-image-diff.1.md)**
|
||||
|
||||
## HISTORY
|
||||
August 2017, Originally compiled by Ryan Cole <rycole@redhat.com>
|
||||
|
|
|
|||
|
|
@ -4,21 +4,29 @@
|
|||
podman-image-diff - Inspect changes on an image's filesystem
|
||||
|
||||
## SYNOPSIS
|
||||
**podman image diff** [*options*] *name*
|
||||
**podman image diff** [*options*] *image* [*image*]
|
||||
|
||||
## DESCRIPTION
|
||||
Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer
|
||||
Displays changes on an image's filesystem. The image will be compared to its parent layer or the second argument when given.
|
||||
|
||||
The output is prefixed with the following symbols:
|
||||
|
||||
| Symbol | Description |
|
||||
|--------|-------------|
|
||||
| A | A file or directory was added. |
|
||||
| D | A file or directory was deleted. |
|
||||
| C | A file or directory was changed. |
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--format**
|
||||
|
||||
Alter the output into a different format. The only valid format for diff is `json`.
|
||||
Alter the output into a different format. The only valid format for **podman image diff** is `json`.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
```
|
||||
# podman diff redis:old redis:alpine
|
||||
$ podman diff redis:old
|
||||
C /usr
|
||||
C /usr/local
|
||||
C /usr/local/bin
|
||||
|
|
@ -26,7 +34,7 @@ A /usr/local/bin/docker-entrypoint.sh
|
|||
```
|
||||
|
||||
```
|
||||
# podman diff --format json redis:old redis:alpine
|
||||
$ podman diff --format json redis:old redis:alpine
|
||||
{
|
||||
"changed": [
|
||||
"/usr",
|
||||
|
|
|
|||
|
|
@ -923,7 +923,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
|
|||
var addToTarFiles []string
|
||||
if !options.IgnoreRootfs {
|
||||
// To correctly track deleted files, let's go through the output of 'podman diff'
|
||||
rootFsChanges, err := c.runtime.GetDiff("", c.ID())
|
||||
rootFsChanges, err := c.runtime.GetDiff("", c.ID(), define.DiffContainer)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error exporting root file-system diff for %q", c.ID())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package define
|
||||
|
||||
// extra type to use as enum
|
||||
type DiffType uint8
|
||||
|
||||
const (
|
||||
// only diff containers
|
||||
DiffContainer DiffType = 1 << iota
|
||||
// only diff images
|
||||
DiffImage
|
||||
// diff both containers and images
|
||||
DiffAll DiffType = 0b11111111
|
||||
)
|
||||
|
||||
func (d DiffType) String() string {
|
||||
switch d {
|
||||
case DiffAll:
|
||||
return "all"
|
||||
case DiffContainer:
|
||||
return "container"
|
||||
case DiffImage:
|
||||
return "image"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package libpod
|
|||
|
||||
import (
|
||||
"github.com/containers/common/libimage"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/libpod/layers"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -21,14 +22,14 @@ var initInodes = map[string]bool{
|
|||
}
|
||||
|
||||
// GetDiff returns the differences between the two images, layers, or containers
|
||||
func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) {
|
||||
toLayer, err := r.getLayerID(to)
|
||||
func (r *Runtime) GetDiff(from, to string, diffType define.DiffType) ([]archive.Change, error) {
|
||||
toLayer, err := r.getLayerID(to, diffType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fromLayer := ""
|
||||
if from != "" {
|
||||
fromLayer, err = r.getLayerID(from)
|
||||
fromLayer, err = r.getLayerID(from, diffType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -49,25 +50,30 @@ func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) {
|
|||
// GetLayerID gets a full layer id given a full or partial id
|
||||
// If the id matches a container or image, the id of the top layer is returned
|
||||
// If the id matches a layer, the top layer id is returned
|
||||
func (r *Runtime) getLayerID(id string) (string, error) {
|
||||
var toLayer string
|
||||
toImage, _, err := r.libimageRuntime.LookupImage(id, &libimage.LookupImageOptions{IgnorePlatform: true})
|
||||
if err == nil {
|
||||
return toImage.TopLayer(), nil
|
||||
func (r *Runtime) getLayerID(id string, diffType define.DiffType) (string, error) {
|
||||
var lastErr error
|
||||
if diffType&define.DiffImage == define.DiffImage {
|
||||
toImage, _, err := r.libimageRuntime.LookupImage(id, &libimage.LookupImageOptions{IgnorePlatform: true})
|
||||
if err == nil {
|
||||
return toImage.TopLayer(), nil
|
||||
}
|
||||
lastErr = err
|
||||
}
|
||||
|
||||
targetID, err := r.store.Lookup(id)
|
||||
if err != nil {
|
||||
targetID = id
|
||||
}
|
||||
toCtr, err := r.store.Container(targetID)
|
||||
if err != nil {
|
||||
toLayer, err = layers.FullID(r.store, targetID)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("layer, image, or container %s does not exist", id)
|
||||
if diffType&define.DiffContainer == define.DiffContainer {
|
||||
toCtr, err := r.store.Container(id)
|
||||
if err == nil {
|
||||
return toCtr.LayerID, nil
|
||||
}
|
||||
} else {
|
||||
toLayer = toCtr.LayerID
|
||||
lastErr = err
|
||||
}
|
||||
return toLayer, nil
|
||||
|
||||
if diffType == define.DiffAll {
|
||||
toLayer, err := layers.FullID(r.store, id)
|
||||
if err == nil {
|
||||
return toLayer, nil
|
||||
}
|
||||
lastErr = err
|
||||
}
|
||||
return "", errors.Wrapf(lastErr, "%s not found", id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,39 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/containers/podman/v3/libpod"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func Changes(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
|
||||
query := struct {
|
||||
Parent string `schema:"parent"`
|
||||
DiffType string `schema:"diffType"`
|
||||
}{}
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||
return
|
||||
}
|
||||
var diffType define.DiffType
|
||||
switch query.DiffType {
|
||||
case "", "all":
|
||||
diffType = define.DiffAll
|
||||
case "container":
|
||||
diffType = define.DiffContainer
|
||||
case "image":
|
||||
diffType = define.DiffImage
|
||||
default:
|
||||
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Errorf("invalid diffType value %q", query.DiffType))
|
||||
return
|
||||
}
|
||||
|
||||
id := utils.GetName(r)
|
||||
changes, err := runtime.GetDiff("", id)
|
||||
changes, err := runtime.GetDiff(query.Parent, id, diffType)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1505,6 +1505,15 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||
// type: string
|
||||
// required: true
|
||||
// description: the name or id of the container
|
||||
// - in: query
|
||||
// name: parent
|
||||
// type: string
|
||||
// description: specify a second layer which is used to compare against it instead of the parent layer
|
||||
// - in: query
|
||||
// name: diffType
|
||||
// type: string
|
||||
// enum: [all, container, image]
|
||||
// description: select what you want to match, default is all
|
||||
// responses:
|
||||
// 200:
|
||||
// description: Array of Changes
|
||||
|
|
|
|||
|
|
@ -1286,7 +1286,16 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||
// name: name
|
||||
// type: string
|
||||
// required: true
|
||||
// description: the name or id of the container
|
||||
// description: the name or id of the image
|
||||
// - in: query
|
||||
// name: parent
|
||||
// type: string
|
||||
// description: specify a second layer which is used to compare against it instead of the parent layer
|
||||
// - in: query
|
||||
// name: diffType
|
||||
// type: string
|
||||
// enum: [all, container, image]
|
||||
// description: select what you want to match, default is all
|
||||
// responses:
|
||||
// 200:
|
||||
// description: Array of Changes
|
||||
|
|
|
|||
|
|
@ -13,13 +13,16 @@ func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive
|
|||
if options == nil {
|
||||
options = new(DiffOptions)
|
||||
}
|
||||
_ = options
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nil, nameOrID)
|
||||
params, err := options.ToParams()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", params, nil, nameOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,12 @@ type CreateOptions struct{}
|
|||
|
||||
//go:generate go run ../generator/generator.go DiffOptions
|
||||
// DiffOptions are optional options for creating containers
|
||||
type DiffOptions struct{}
|
||||
type DiffOptions struct {
|
||||
// By the default diff will compare against the parent layer. Change the Parent if you want to compare against something else.
|
||||
Parent *string
|
||||
// Change the type the backend should match. This can be set to "all", "container" or "image".
|
||||
DiffType *string
|
||||
}
|
||||
|
||||
//go:generate go run ../generator/generator.go ExecInspectOptions
|
||||
// ExecInspectOptions are optional options for inspecting
|
||||
|
|
|
|||
|
|
@ -19,3 +19,35 @@ func (o *DiffOptions) Changed(fieldName string) bool {
|
|||
func (o *DiffOptions) ToParams() (url.Values, error) {
|
||||
return util.ToParams(o)
|
||||
}
|
||||
|
||||
// WithParent
|
||||
func (o *DiffOptions) WithParent(value string) *DiffOptions {
|
||||
v := &value
|
||||
o.Parent = v
|
||||
return o
|
||||
}
|
||||
|
||||
// GetParent
|
||||
func (o *DiffOptions) GetParent() string {
|
||||
var parent string
|
||||
if o.Parent == nil {
|
||||
return parent
|
||||
}
|
||||
return *o.Parent
|
||||
}
|
||||
|
||||
// WithDiffType
|
||||
func (o *DiffOptions) WithDiffType(value string) *DiffOptions {
|
||||
v := &value
|
||||
o.DiffType = v
|
||||
return o
|
||||
}
|
||||
|
||||
// GetDiffType
|
||||
func (o *DiffOptions) GetDiffType() string {
|
||||
var diffType string
|
||||
if o.DiffType == nil {
|
||||
return diffType
|
||||
}
|
||||
return *o.DiffType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ type RemoveOptions struct {
|
|||
//go:generate go run ../generator/generator.go DiffOptions
|
||||
// DiffOptions are optional options image diffs
|
||||
type DiffOptions struct {
|
||||
// By the default diff will compare against the parent layer. Change the Parent if you want to compare against something else.
|
||||
Parent *string
|
||||
// Change the type the backend should match. This can be set to "all", "container" or "image".
|
||||
DiffType *string
|
||||
}
|
||||
|
||||
//go:generate go run ../generator/generator.go ListOptions
|
||||
|
|
|
|||
|
|
@ -19,3 +19,35 @@ func (o *DiffOptions) Changed(fieldName string) bool {
|
|||
func (o *DiffOptions) ToParams() (url.Values, error) {
|
||||
return util.ToParams(o)
|
||||
}
|
||||
|
||||
// WithParent
|
||||
func (o *DiffOptions) WithParent(value string) *DiffOptions {
|
||||
v := &value
|
||||
o.Parent = v
|
||||
return o
|
||||
}
|
||||
|
||||
// GetParent
|
||||
func (o *DiffOptions) GetParent() string {
|
||||
var parent string
|
||||
if o.Parent == nil {
|
||||
return parent
|
||||
}
|
||||
return *o.Parent
|
||||
}
|
||||
|
||||
// WithDiffType
|
||||
func (o *DiffOptions) WithDiffType(value string) *DiffOptions {
|
||||
v := &value
|
||||
o.DiffType = v
|
||||
return o
|
||||
}
|
||||
|
||||
// GetDiffType
|
||||
func (o *DiffOptions) GetDiffType() string {
|
||||
var diffType string
|
||||
if o.DiffType == nil {
|
||||
return diffType
|
||||
}
|
||||
return *o.DiffType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ type ContainerEngine interface {
|
|||
ContainerCopyFromArchive(ctx context.Context, nameOrID, path string, reader io.Reader, options CopyOptions) (ContainerCopyFunc, error)
|
||||
ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (ContainerCopyFunc, error)
|
||||
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
|
||||
ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
|
||||
ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
|
||||
ContainerExecDetached(ctx context.Context, nameOrID string, options ExecOptions) (string, error)
|
||||
ContainerExists(ctx context.Context, nameOrID string, options ContainerExistsOptions) (*BoolReport, error)
|
||||
|
|
@ -52,6 +51,7 @@ type ContainerEngine interface {
|
|||
ContainerUnmount(ctx context.Context, nameOrIDs []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error)
|
||||
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
|
||||
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
|
||||
Diff(ctx context.Context, namesOrIds []string, options DiffOptions) (*DiffReport, error)
|
||||
Events(ctx context.Context, opts EventsOptions) error
|
||||
GenerateSystemd(ctx context.Context, nameOrID string, opts GenerateSystemdOptions) (*GenerateSystemdReport, error)
|
||||
GenerateKube(ctx context.Context, nameOrIDs []string, opts GenerateKubeOptions) (*GenerateKubeReport, error)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
type ImageEngine interface {
|
||||
Build(ctx context.Context, containerFiles []string, opts BuildOptions) (*BuildReport, error)
|
||||
Config(ctx context.Context) (*config.Config, error)
|
||||
Diff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
|
||||
Exists(ctx context.Context, nameOrID string) (*BoolReport, error)
|
||||
History(ctx context.Context, nameOrID string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
|
||||
Import(ctx context.Context, opts ImageImportOptions) (*ImageImportReport, error)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net"
|
||||
|
||||
buildahDefine "github.com/containers/buildah/define"
|
||||
"github.com/containers/podman/v3/libpod/define"
|
||||
"github.com/containers/podman/v3/libpod/events"
|
||||
"github.com/containers/podman/v3/pkg/specgen"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
|
|
@ -62,9 +63,10 @@ type InspectOptions struct {
|
|||
|
||||
// All API and CLI diff commands and diff sub-commands use the same options
|
||||
type DiffOptions struct {
|
||||
Format string `json:",omitempty"` // CLI only
|
||||
Latest bool `json:",omitempty"` // API and CLI, only supported by containers
|
||||
Archive bool `json:",omitempty"` // CLI only
|
||||
Format string `json:",omitempty"` // CLI only
|
||||
Latest bool `json:",omitempty"` // API and CLI, only supported by containers
|
||||
Archive bool `json:",omitempty"` // CLI only
|
||||
Type define.DiffType // Type which should be compared
|
||||
}
|
||||
|
||||
// DiffReport provides changes for object
|
||||
|
|
|
|||
|
|
@ -858,16 +858,26 @@ func (ic *ContainerEngine) ContainerListExternal(ctx context.Context) ([]entitie
|
|||
return ps.GetExternalContainerLists(ic.Libpod)
|
||||
}
|
||||
|
||||
// ContainerDiff provides changes to given container
|
||||
func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, opts entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
// Diff provides changes to given container
|
||||
func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
var (
|
||||
base string
|
||||
parent string
|
||||
)
|
||||
if opts.Latest {
|
||||
ctnr, err := ic.Libpod.GetLatestContainer()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get latest container")
|
||||
}
|
||||
nameOrID = ctnr.ID()
|
||||
base = ctnr.ID()
|
||||
}
|
||||
changes, err := ic.Libpod.GetDiff("", nameOrID)
|
||||
if len(namesOrIDs) > 0 {
|
||||
base = namesOrIDs[0]
|
||||
if len(namesOrIDs) > 1 {
|
||||
parent = namesOrIDs[1]
|
||||
}
|
||||
}
|
||||
changes, err := ic.Libpod.GetDiff(parent, base, opts.Type)
|
||||
return &entities.DiffReport{Changes: changes}, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -403,14 +403,6 @@ func (ir *ImageEngine) Import(ctx context.Context, options entities.ImageImportO
|
|||
return &entities.ImageImportReport{Id: imageID}, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
changes, err := ir.Libpod.GetDiff("", nameOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &entities.DiffReport{Changes: changes}, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
|
||||
filter, err := libimage.ParseSearchFilter(opts.Filters)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -765,8 +765,18 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
|||
return &report, err
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
changes, err := containers.Diff(ic.ClientCtx, nameOrID, nil)
|
||||
func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
var base string
|
||||
options := new(containers.DiffOptions).WithDiffType(opts.Type.String())
|
||||
if len(namesOrIDs) > 0 {
|
||||
base = namesOrIDs[0]
|
||||
if len(namesOrIDs) > 1 {
|
||||
options.WithParent(namesOrIDs[1])
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("no arguments for diff")
|
||||
}
|
||||
changes, err := containers.Diff(ic.ClientCtx, base, options)
|
||||
return &entities.DiffReport{Changes: changes}, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -299,16 +299,6 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string,
|
|||
return utils2.UntarToFileSystem(opts.Output, f, nil)
|
||||
}
|
||||
|
||||
// Diff reports the changes to the given image
|
||||
func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
|
||||
options := new(images.DiffOptions)
|
||||
changes, err := images.Diff(ir.ClientCtx, nameOrID, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &entities.DiffReport{Changes: changes}, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
|
||||
mappedFilters := make(map[string][]string)
|
||||
filters, err := libimage.ParseSearchFilter(opts.Filters)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
. "github.com/containers/podman/v3/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
|
@ -40,13 +42,6 @@ var _ = Describe("Podman diff", func() {
|
|||
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
|
||||
})
|
||||
|
||||
It("podman container diff of image", func() {
|
||||
session := podmanTest.Podman([]string{"container", "diff", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
|
||||
})
|
||||
|
||||
It("podman diff bogus image", func() {
|
||||
session := podmanTest.Podman([]string{"diff", "1234"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
|
@ -84,7 +79,11 @@ var _ = Describe("Podman diff", func() {
|
|||
session := podmanTest.Podman([]string{"run", "--name", "diff-test", ALPINE, "touch", "/tmp/diff-test"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
session = podmanTest.Podman([]string{"diff", "diff-test"})
|
||||
if !IsRemote() {
|
||||
session = podmanTest.Podman([]string{"diff", "-l"})
|
||||
} else {
|
||||
session = podmanTest.Podman([]string{"diff", "diff-test"})
|
||||
}
|
||||
session.WaitWithDefaultTimeout()
|
||||
containerDiff := session.OutputToStringArray()
|
||||
sort.Strings(containerDiff)
|
||||
|
|
@ -92,4 +91,101 @@ var _ = Describe("Podman diff", func() {
|
|||
Expect(session.LineInOutputContains("A /tmp/diff-test")).To(BeTrue())
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman image diff", func() {
|
||||
file1 := "/" + stringid.GenerateNonCryptoID()
|
||||
file2 := "/" + stringid.GenerateNonCryptoID()
|
||||
file3 := "/" + stringid.GenerateNonCryptoID()
|
||||
|
||||
// Create container image with the files
|
||||
containerfile := fmt.Sprintf(`
|
||||
FROM %s
|
||||
RUN touch %s
|
||||
RUN touch %s
|
||||
RUN touch %s`, ALPINE, file1, file2, file3)
|
||||
|
||||
image := "podman-diff-test"
|
||||
podmanTest.BuildImage(containerfile, image, "true")
|
||||
|
||||
// build a second image which used as base to compare against
|
||||
// using ALPINE does not work in CI, most likely due the extra vfs.imagestore
|
||||
containerfile = fmt.Sprintf(`
|
||||
FROM %s
|
||||
RUN echo test
|
||||
`, ALPINE)
|
||||
baseImage := "base-image"
|
||||
podmanTest.BuildImage(containerfile, baseImage, "true")
|
||||
|
||||
session := podmanTest.Podman([]string{"image", "diff", image})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 1))
|
||||
Expect(session.OutputToString()).To(Equal("A " + file3))
|
||||
|
||||
session = podmanTest.Podman([]string{"image", "diff", image, baseImage})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 4))
|
||||
Expect(session.LineInOutputContains("A " + file1)).To(BeTrue())
|
||||
Expect(session.LineInOutputContains("A " + file2)).To(BeTrue())
|
||||
Expect(session.LineInOutputContains("A " + file3)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("podman image diff of single image", func() {
|
||||
session := podmanTest.Podman([]string{"image", "diff", BB})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
|
||||
})
|
||||
|
||||
It("podman image diff bogus image", func() {
|
||||
session := podmanTest.Podman([]string{"image", "diff", "1234", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
})
|
||||
|
||||
It("podman image diff of the same image", func() {
|
||||
session := podmanTest.Podman([]string{"image", "diff", ALPINE, ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 0))
|
||||
})
|
||||
|
||||
It("podman diff container and image with same name", func() {
|
||||
imagefile := "/" + stringid.GenerateNonCryptoID()
|
||||
confile := "/" + stringid.GenerateNonCryptoID()
|
||||
|
||||
// Create container image with the files
|
||||
containerfile := fmt.Sprintf(`
|
||||
FROM %s
|
||||
RUN touch %s`, ALPINE, imagefile)
|
||||
|
||||
name := "podman-diff-test"
|
||||
podmanTest.BuildImage(containerfile, name, "false")
|
||||
|
||||
session := podmanTest.Podman([]string{"run", "--name", name, ALPINE, "touch", confile})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
// podman diff prefers image over container when they have the same name
|
||||
session = podmanTest.Podman([]string{"diff", name})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 2))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imagefile))
|
||||
|
||||
session = podmanTest.Podman([]string{"image", "diff", name})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 2))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(imagefile))
|
||||
|
||||
// container diff has to show the container
|
||||
session = podmanTest.Podman([]string{"container", "diff", name})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 2))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(confile))
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue