summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJhon Honce <jhonce@redhat.com>2020-04-06 16:40:32 -0700
committerJhon Honce <jhonce@redhat.com>2020-04-07 09:39:46 -0700
commit8ae28a55acc51a02597b23140916a690fbbdc3fc (patch)
tree735d876be3204dcd54c7e739083cc706dec83101
parent44f910c28cae178eab9ad439587355fa4927dab7 (diff)
downloadpodman-8ae28a55acc51a02597b23140916a690fbbdc3fc.tar.gz
podman-8ae28a55acc51a02597b23140916a690fbbdc3fc.tar.bz2
podman-8ae28a55acc51a02597b23140916a690fbbdc3fc.zip
V2 podman diff(changes) support
* Ported CLI command * Added API endpoint * Added bindings * Updated swagger (TODO: n endpoints, one handler) Signed-off-by: Jhon Honce <jhonce@redhat.com>
-rw-r--r--cmd/podmanV2/containers/diff.go67
-rw-r--r--cmd/podmanV2/diff.go74
-rw-r--r--cmd/podmanV2/images/diff.go63
-rw-r--r--cmd/podmanV2/inspect.go2
-rw-r--r--cmd/podmanV2/registry/registry.go8
-rw-r--r--cmd/podmanV2/report/diff.go44
-rw-r--r--pkg/api/handlers/compat/changes.go20
-rw-r--r--pkg/api/handlers/compat/swagger.go10
-rw-r--r--pkg/api/server/register_containers.go35
-rw-r--r--pkg/api/server/register_images.go31
-rw-r--r--pkg/bindings/containers/diff.go24
-rw-r--r--pkg/bindings/images/diff.go24
-rw-r--r--pkg/domain/entities/engine_container.go13
-rw-r--r--pkg/domain/entities/engine_image.go9
-rw-r--r--pkg/domain/entities/types.go13
-rw-r--r--pkg/domain/infra/abi/containers.go17
-rw-r--r--pkg/domain/infra/abi/images.go8
-rw-r--r--pkg/domain/infra/tunnel/containers.go5
-rw-r--r--pkg/domain/infra/tunnel/images.go9
19 files changed, 462 insertions, 14 deletions
diff --git a/cmd/podmanV2/containers/diff.go b/cmd/podmanV2/containers/diff.go
new file mode 100644
index 000000000..3009cdfad
--- /dev/null
+++ b/cmd/podmanV2/containers/diff.go
@@ -0,0 +1,67 @@
+package containers
+
+import (
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/report"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // podman container _diff_
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] CONTAINER",
+ Args: registry.IdOrLatestArgs,
+ Short: "Inspect changes on container's file systems",
+ Long: `Displays changes on a container filesystem. The container will be compared to its parent layer.`,
+ PreRunE: preRunE,
+ RunE: diff,
+ Example: `podman container diff myCtr
+ podman container diff -l --format json myCtr`,
+ }
+ diffOpts *entities.DiffOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ Parent: containerCmd,
+ })
+
+ diffOpts = &entities.DiffOptions{}
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+
+ if !registry.IsRemote() {
+ flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ }
+}
+
+func diff(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")
+ }
+
+ results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), args[0], entities.DiffOptions{})
+ if err != nil {
+ return err
+ }
+
+ switch diffOpts.Format {
+ case "":
+ return report.ChangesToTable(results)
+ case "json":
+ return report.ChangesToJSON(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)
+}
diff --git a/cmd/podmanV2/diff.go b/cmd/podmanV2/diff.go
new file mode 100644
index 000000000..6e4263370
--- /dev/null
+++ b/cmd/podmanV2/diff.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/containers"
+ "github.com/containers/libpod/cmd/podmanV2/images"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+// Inspect is one of the outlier commands in that it operates on images/containers/...
+
+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.`
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] {CONTAINER_ID | IMAGE_ID}",
+ Args: registry.IdOrLatestArgs,
+ Short: "Display the changes of object's file system",
+ Long: diffDescription,
+ TraverseChildren: true,
+ RunE: diff,
+ Example: `podman diff imageID
+ podman diff ctrID
+ podman diff --format json redis:alpine`,
+ }
+
+ diffOpts = entities.DiffOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ })
+ diffCmd.SetHelpTemplate(registry.HelpTemplate())
+ diffCmd.SetUsageTemplate(registry.UsageTemplate())
+
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+
+ if !registry.IsRemote() {
+ flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ }
+}
+
+func diff(cmd *cobra.Command, args []string) error {
+ ie, err := registry.NewImageEngine(cmd, args)
+ if err != nil {
+ return err
+ }
+
+ if found, err := ie.Exists(registry.GetContext(), args[0]); err != nil {
+ return err
+ } else if found.Value {
+ return images.Diff(cmd, args, diffOpts)
+ }
+
+ ce, err := registry.NewContainerEngine(cmd, args)
+ if err != nil {
+ return err
+ }
+
+ if found, err := ce.ContainerExists(registry.GetContext(), args[0]); err != nil {
+ return err
+ } else if found.Value {
+ return containers.Diff(cmd, args, diffOpts)
+ }
+ return fmt.Errorf("%s not found on system", args[0])
+}
diff --git a/cmd/podmanV2/images/diff.go b/cmd/podmanV2/images/diff.go
new file mode 100644
index 000000000..e913a603a
--- /dev/null
+++ b/cmd/podmanV2/images/diff.go
@@ -0,0 +1,63 @@
+package images
+
+import (
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/report"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // podman container _inspect_
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] CONTAINER",
+ Args: registry.IdOrLatestArgs,
+ Short: "Inspect changes on image's file systems",
+ Long: `Displays changes on a image's filesystem. The image will be compared to its parent layer.`,
+ PreRunE: preRunE,
+ RunE: diff,
+ Example: `podman image diff myImage
+ podman image diff --format json redis:alpine`,
+ }
+ diffOpts *entities.DiffOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ Parent: imageCmd,
+ })
+
+ diffOpts = &entities.DiffOptions{}
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+}
+
+func diff(cmd *cobra.Command, args []string) error {
+ if len(args) == 0 && !diffOpts.Latest {
+ return errors.New("image must be specified: podman image diff [options [...]] ID-NAME")
+ }
+
+ results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], entities.DiffOptions{})
+ if err != nil {
+ return err
+ }
+
+ switch diffOpts.Format {
+ case "":
+ return report.ChangesToTable(results)
+ case "json":
+ return report.ChangesToJSON(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)
+}
diff --git a/cmd/podmanV2/inspect.go b/cmd/podmanV2/inspect.go
index 4975cf632..15d7579ea 100644
--- a/cmd/podmanV2/inspect.go
+++ b/cmd/podmanV2/inspect.go
@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
-// Inspect is one of the out layer commands in that it operates on images/containers/...
+// Inspect is one of the outlier commands in that it operates on images/containers/...
var (
inspectOpts *entities.InspectOptions
diff --git a/cmd/podmanV2/registry/registry.go b/cmd/podmanV2/registry/registry.go
index 401f82718..8ff44041f 100644
--- a/cmd/podmanV2/registry/registry.go
+++ b/cmd/podmanV2/registry/registry.go
@@ -113,6 +113,14 @@ func SubCommandExists(cmd *cobra.Command, args []string) error {
return errors.Errorf("missing command '%[1]s COMMAND'\nTry '%[1]s --help' for more information.", cmd.CommandPath())
}
+// IdOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
+func IdOrLatestArgs(cmd *cobra.Command, args []string) error {
+ if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
+ return errors.New(`command requires a name, id or the "--latest" flag`)
+ }
+ return nil
+}
+
type podmanContextKey string
var podmanFactsKey = podmanContextKey("engineOptions")
diff --git a/cmd/podmanV2/report/diff.go b/cmd/podmanV2/report/diff.go
new file mode 100644
index 000000000..b36189d75
--- /dev/null
+++ b/cmd/podmanV2/report/diff.go
@@ -0,0 +1,44 @@
+package report
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/storage/pkg/archive"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+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)
+ }
+ }
+
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ enc := json.NewEncoder(os.Stdout)
+ return enc.Encode(body)
+}
+
+func ChangesToTable(diffs *entities.DiffReport) error {
+ for _, row := range diffs.Changes {
+ fmt.Fprintln(os.Stdout, row.String())
+ }
+ return nil
+}
diff --git a/pkg/api/handlers/compat/changes.go b/pkg/api/handlers/compat/changes.go
new file mode 100644
index 000000000..6907c487e
--- /dev/null
+++ b/pkg/api/handlers/compat/changes.go
@@ -0,0 +1,20 @@
+package compat
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+)
+
+func Changes(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ id := utils.GetName(r)
+ changes, err := runtime.GetDiff("", id)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteJSON(w, 200, changes)
+}
diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go
index cbd8e61fb..f1aabf987 100644
--- a/pkg/api/handlers/compat/swagger.go
+++ b/pkg/api/handlers/compat/swagger.go
@@ -2,6 +2,7 @@ package compat
import (
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/storage/pkg/archive"
)
// Create container
@@ -25,3 +26,12 @@ type swagCtrWaitResponse struct {
}
}
}
+
+// Object Changes
+// swagger:response Changes
+type swagChangesResponse struct {
+ // in:body
+ Body struct {
+ Changes []archive.Change
+ }
+}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index f126112d0..150cca872 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -1377,5 +1377,40 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name}/restore"), s.APIHandler(libpod.Restore)).Methods(http.MethodPost)
+
+ // swagger:operation GET /containers/{name}/changes libpod libpodChangesContainer
+ // swagger:operation GET /libpod/containers/{name}/changes compat changesContainer
+ // ---
+ // tags:
+ // - containers
+ // - containers (compat)
+ // summary: Report on changes to container's filesystem; adds, deletes or modifications.
+ // description: |
+ // Returns which files in a container's filesystem have been added, deleted, or modified. The Kind of modification can be one of:
+ //
+ // 0: Modified
+ // 1: Added
+ // 2: Deleted
+ // parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: the name or id of the container
+ // responses:
+ // 200:
+ // description: Array of Changes
+ // content:
+ // application/json:
+ // schema:
+ // $ref: "#/responses/Changes"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/changes"), s.APIHandler(compat.Changes))
+ r.HandleFunc("/containers/{name}/changes", s.APIHandler(compat.Changes))
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/changes"), s.APIHandler(compat.Changes))
+
return nil
}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index d45423096..77560e789 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -1125,5 +1125,36 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/{name:.*}/untag"), s.APIHandler(libpod.UntagImage)).Methods(http.MethodPost)
+
+ // swagger:operation GET /libpod/images/{name}/changes libpod libpodChangesImages
+ // ---
+ // tags:
+ // - images
+ // summary: Report on changes to images's filesystem; adds, deletes or modifications.
+ // description: |
+ // Returns which files in a images's filesystem have been added, deleted, or modified. The Kind of modification can be one of:
+ //
+ // 0: Modified
+ // 1: Added
+ // 2: Deleted
+ // parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: the name or id of the container
+ // responses:
+ // 200:
+ // description: Array of Changes
+ // content:
+ // application/json:
+ // schema:
+ // $ref: "#/responses/Changes"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/images/{name}/changes"), s.APIHandler(compat.Changes))
+
return nil
}
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
new file mode 100644
index 000000000..82070ca9a
--- /dev/null
+++ b/pkg/bindings/containers/diff.go
@@ -0,0 +1,24 @@
+package containers
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/storage/pkg/archive"
+)
+
+// Diff provides the changes between two container layers
+func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ var changes []archive.Change
+ return changes, response.Process(&changes)
+}
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
new file mode 100644
index 000000000..cfdd06a97
--- /dev/null
+++ b/pkg/bindings/images/diff.go
@@ -0,0 +1,24 @@
+package images
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/storage/pkg/archive"
+)
+
+// Diff provides the changes between two container layers
+func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ var changes []archive.Change
+ return changes, response.Process(&changes)
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 576ce1658..e7fa67209 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -9,18 +9,19 @@ import (
type ContainerEngine interface {
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
- ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error)
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
- ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
+ ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, 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) (int, error)
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
- ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
+ ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
- ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error)
+ ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
+ ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
@@ -29,9 +30,9 @@ type ContainerEngine interface {
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
-
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
+ PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, error)
@@ -41,8 +42,6 @@ type ContainerEngine interface {
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error)
- PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
-
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index a28bfc548..16b96e9ef 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -6,16 +6,17 @@ import (
type ImageEngine interface {
Delete(ctx context.Context, nameOrId []string, opts ImageDeleteOptions) (*ImageDeleteReport, 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)
Inspect(ctx context.Context, names []string, opts InspectOptions) (*ImageInspectReport, error)
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
+ Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
- Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
- Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
- Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
- Import(ctx context.Context, opts ImageImportOptions) (*ImageImportReport, error)
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
+ Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
+ Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
}
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index dd7aaa07f..7e35957f4 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -4,6 +4,7 @@ import (
"net"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/storage/pkg/archive"
"github.com/cri-o/ocicni/pkg/ocicni"
)
@@ -49,3 +50,15 @@ type InspectOptions struct {
Latest bool `json:",omitempty"`
Size bool `json:",omitempty"`
}
+
+// 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
+}
+
+// DiffReport provides changes for object
+type DiffReport struct {
+ Changes []archive.Change
+}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 828ee56f0..ccbe6d4fd 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -599,9 +599,9 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
ExitCode: 125,
}
if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
- //if lastError != nil {
+ // if lastError != nil {
// fmt.Fprintln(os.Stderr, lastError)
- //}
+ // }
report.Err = err
if errors.Cause(err) == define.ErrWillDeadlock {
report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
@@ -623,6 +623,19 @@ func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.C
return ps.GetContainerLists(ic.Libpod, options)
}
+// ContainerDiff provides changes to given container
+func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, opts entities.DiffOptions) (*entities.DiffReport, error) {
+ if opts.Latest {
+ ctnr, err := ic.Libpod.GetLatestContainer()
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to get latest container")
+ }
+ nameOrId = ctnr.ID()
+ }
+ changes, err := ic.Libpod.GetDiff("", nameOrId)
+ return &entities.DiffReport{Changes: changes}, err
+}
+
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
var (
joinPod bool
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 9d706a112..2edef2723 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -413,3 +413,11 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string,
}
return newImage.Save(ctx, nameOrId, options.Format, options.Output, tags, options.Quiet, options.Compress)
}
+
+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
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index e96200c5b..b22c6e3ba 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -324,3 +324,8 @@ func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.C
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
return nil, errors.New("not implemented")
}
+
+func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) {
+ changes, err := containers.Diff(ic.ClientCxt, nameOrId)
+ return &entities.DiffReport{Changes: changes}, err
+}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 516914a68..66abd7f47 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -241,3 +241,12 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string,
}
return utils2.UntarToFileSystem(options.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) {
+ changes, err := images.Diff(ir.ClientCxt, nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.DiffReport{Changes: changes}, nil
+}