mirror of
https://github.com/containers/podman.git
synced 2025-06-24 03:08:13 +08:00
Merge pull request #5739 from jwhonce/wip/diff
V2 Podman diff(changes) support
This commit is contained in:
67
cmd/podmanV2/containers/diff.go
Normal file
67
cmd/podmanV2/containers/diff.go
Normal file
@ -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)
|
||||||
|
}
|
74
cmd/podmanV2/diff.go
Normal file
74
cmd/podmanV2/diff.go
Normal file
@ -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])
|
||||||
|
}
|
63
cmd/podmanV2/images/diff.go
Normal file
63
cmd/podmanV2/images/diff.go
Normal file
@ -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)
|
||||||
|
}
|
@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"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 (
|
var (
|
||||||
inspectOpts *entities.InspectOptions
|
inspectOpts *entities.InspectOptions
|
||||||
|
@ -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())
|
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
|
type podmanContextKey string
|
||||||
|
|
||||||
var podmanFactsKey = podmanContextKey("engineOptions")
|
var podmanFactsKey = podmanContextKey("engineOptions")
|
||||||
|
44
cmd/podmanV2/report/diff.go
Normal file
44
cmd/podmanV2/report/diff.go
Normal file
@ -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
|
||||||
|
}
|
20
pkg/api/handlers/compat/changes.go
Normal file
20
pkg/api/handlers/compat/changes.go
Normal file
@ -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)
|
||||||
|
}
|
@ -2,6 +2,7 @@ package compat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||||
|
"github.com/containers/storage/pkg/archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create container
|
// Create container
|
||||||
@ -25,3 +26,12 @@ type swagCtrWaitResponse struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Object Changes
|
||||||
|
// swagger:response Changes
|
||||||
|
type swagChangesResponse struct {
|
||||||
|
// in:body
|
||||||
|
Body struct {
|
||||||
|
Changes []archive.Change
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1377,5 +1377,40 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// 500:
|
// 500:
|
||||||
// $ref: "#/responses/InternalError"
|
// $ref: "#/responses/InternalError"
|
||||||
r.HandleFunc(VersionedPath("/libpod/containers/{name}/restore"), s.APIHandler(libpod.Restore)).Methods(http.MethodPost)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1125,5 +1125,36 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||||||
// 500:
|
// 500:
|
||||||
// $ref: '#/responses/InternalError'
|
// $ref: '#/responses/InternalError'
|
||||||
r.Handle(VersionedPath("/libpod/images/{name:.*}/untag"), s.APIHandler(libpod.UntagImage)).Methods(http.MethodPost)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
24
pkg/bindings/containers/diff.go
Normal file
24
pkg/bindings/containers/diff.go
Normal file
@ -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)
|
||||||
|
}
|
24
pkg/bindings/images/diff.go
Normal file
24
pkg/bindings/images/diff.go
Normal file
@ -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)
|
||||||
|
}
|
@ -9,18 +9,19 @@ import (
|
|||||||
|
|
||||||
type ContainerEngine interface {
|
type ContainerEngine interface {
|
||||||
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
|
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)
|
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)
|
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)
|
ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, error)
|
||||||
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, 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
|
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)
|
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)
|
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)
|
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)
|
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
||||||
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
|
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
|
||||||
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, 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)
|
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
|
||||||
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
|
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
|
||||||
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
|
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
|
||||||
|
|
||||||
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
|
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
|
||||||
PodExists(ctx context.Context, nameOrId string) (*BoolReport, 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)
|
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
|
||||||
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
|
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
|
||||||
PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, 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)
|
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
|
||||||
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
|
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
|
||||||
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, 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)
|
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error)
|
||||||
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
|
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
|
||||||
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
|
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
|
||||||
|
@ -6,16 +6,17 @@ import (
|
|||||||
|
|
||||||
type ImageEngine interface {
|
type ImageEngine interface {
|
||||||
Delete(ctx context.Context, nameOrId []string, opts ImageDeleteOptions) (*ImageDeleteReport, error)
|
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)
|
Exists(ctx context.Context, nameOrId string) (*BoolReport, error)
|
||||||
History(ctx context.Context, nameOrId string, opts ImageHistoryOptions) (*ImageHistoryReport, 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)
|
Inspect(ctx context.Context, names []string, opts InspectOptions) (*ImageInspectReport, error)
|
||||||
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, 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)
|
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
|
||||||
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, 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
|
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
|
||||||
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) 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
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containers/libpod/pkg/specgen"
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
|
"github.com/containers/storage/pkg/archive"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,3 +50,15 @@ type InspectOptions struct {
|
|||||||
Latest bool `json:",omitempty"`
|
Latest bool `json:",omitempty"`
|
||||||
Size 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
|
||||||
|
}
|
||||||
|
@ -599,9 +599,9 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
|
|||||||
ExitCode: 125,
|
ExitCode: 125,
|
||||||
}
|
}
|
||||||
if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
|
if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
|
||||||
//if lastError != nil {
|
// if lastError != nil {
|
||||||
// fmt.Fprintln(os.Stderr, lastError)
|
// fmt.Fprintln(os.Stderr, lastError)
|
||||||
//}
|
// }
|
||||||
report.Err = err
|
report.Err = err
|
||||||
if errors.Cause(err) == define.ErrWillDeadlock {
|
if errors.Cause(err) == define.ErrWillDeadlock {
|
||||||
report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
|
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)
|
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) {
|
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
|
||||||
var (
|
var (
|
||||||
joinPod bool
|
joinPod bool
|
||||||
|
@ -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)
|
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
|
||||||
|
}
|
||||||
|
@ -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) {
|
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
|
||||||
return nil, errors.New("not implemented")
|
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
|
||||||
|
}
|
||||||
|
@ -241,3 +241,12 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string,
|
|||||||
}
|
}
|
||||||
return utils2.UntarToFileSystem(options.Output, f, nil)
|
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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user