mirror of https://github.com/containers/podman.git
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>
This commit is contained in:
parent
44f910c28c
commit
8ae28a55ac
|
@ -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)
|
||||
}
|
|
@ -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])
|
||||
}
|
|
@ -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"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 (
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue