Merge pull request #722 from 14rcole/kpod-diff

Add kpod diff command
This commit is contained in:
Mrunal Patel 2017-08-12 08:17:19 -07:00 committed by GitHub
commit 2bdcd460bb
6 changed files with 238 additions and 0 deletions

89
cmd/kpod/diff.go Normal file
View file

@ -0,0 +1,89 @@
package main
import (
"encoding/json"
"fmt"
"github.com/containers/storage/pkg/archive"
"github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
type diffJSONOutput struct {
Changed []string `json:"changed,omitempty"`
Added []string `json:"added,omitempty"`
Deleted []string `json:"deleted,omitempty"`
}
var (
diffFlags = []cli.Flag{
cli.BoolFlag{
Name: "archive",
Usage: "Save the diff as a tar archive",
Hidden: true,
},
cli.BoolFlag{
Name: "json",
Usage: "Format output as JSON",
},
}
diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The
container or image will be compared to its parent layer`)
diffCommand = cli.Command{
Name: "diff",
Usage: "Inspect changes on container's file systems",
Description: diffDescription,
Flags: diffFlags,
Action: diffCmd,
ArgsUsage: "ID-NAME",
}
)
func diffCmd(c *cli.Context) error {
if len(c.Args()) != 1 {
return errors.Errorf("container, layer, or image name must be specified: kpod diff [options [...]] ID-NAME")
}
config, err := getConfig(c)
if err != nil {
return errors.Wrapf(err, "could not get config")
}
server, err := libkpod.New(config)
if err != nil {
return errors.Wrapf(err, "could not get container server")
}
to := c.Args().Get(0)
changes, err := server.GetDiff("", to)
if err != nil {
return errors.Wrapf(err, "could not get changes for %q", to)
}
if c.Bool("json") {
jsonStruct := diffJSONOutput{}
for _, change := range changes {
if change.Kind == archive.ChangeModify {
jsonStruct.Changed = append(jsonStruct.Changed, change.Path)
} else if change.Kind == archive.ChangeAdd {
jsonStruct.Added = append(jsonStruct.Added, change.Path)
} else if change.Kind == archive.ChangeDelete {
jsonStruct.Deleted = append(jsonStruct.Deleted, change.Path)
} else {
return errors.Errorf("change kind %q not recognized", change.Kind.String())
}
}
b, err := json.MarshalIndent(jsonStruct, "", " ")
if err != nil {
return errors.Wrapf(err, "could not marshal json for %+v", jsonStruct)
}
fmt.Println(string(b))
} else {
for _, change := range changes {
fmt.Println(change.String())
}
}
return nil
}

View file

@ -22,6 +22,7 @@ func main() {
app.Version = Version app.Version = Version
app.Commands = []cli.Command{ app.Commands = []cli.Command{
diffCommand,
exportCommand, exportCommand,
historyCommand, historyCommand,
imagesCommand, imagesCommand,

45
docs/kpod-diff.1.md Normal file
View file

@ -0,0 +1,45 @@
% kpod(1) kpod-diff - Inspect changes on a container or image's filesystem
% Dan Walsh
# kpod-diff "1" "August 2017" "kpod"
## NAME
kpod diff - Inspect changes on a container or image's filesystem
## SYNOPSIS
**kpod** **diff** [*options* [...]] NAME
## DESCRIPTION
Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer
## OPTIONS
**--json**
Format output as json
## EXAMPLE
kpod diff redis:alpine
C /usr
C /usr/local
C /usr/local/bin
A /usr/local/bin/docker-entrypoint.sh
kpod diff --json redis:alpine
{
"changed": [
"/usr",
"/usr/local",
"/usr/local/bin"
],
"added": [
"/usr/local/bin/docker-entrypoint.sh"
]
}
## SEE ALSO
kpod(1)
## HISTORY
August 2017, Originally compiled by Ryan Cole <rycole@redhat.com>

54
libkpod/diff.go Normal file
View file

@ -0,0 +1,54 @@
package libkpod
import (
"github.com/containers/storage/pkg/archive"
"github.com/kubernetes-incubator/cri-o/libkpod/image"
"github.com/kubernetes-incubator/cri-o/libkpod/layer"
"github.com/pkg/errors"
)
// GetDiff returns the differences betwen the two images, layers, or containers
func (c *ContainerServer) GetDiff(from, to string) ([]archive.Change, error) {
toLayer, err := c.getLayerID(to)
if err != nil {
return nil, err
}
fromLayer := ""
if from != "" {
fromLayer, err = c.getLayerID(from)
if err != nil {
return nil, err
}
}
return c.Store().Changes(fromLayer, toLayer)
}
// 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 (c *ContainerServer) getLayerID(id string) (string, error) {
var toLayer string
toImage, err := image.FindImage(c.store, id)
if err != nil {
toCtr, err := c.store.Container(id)
if err != nil {
toLayer, err = layer.FullID(c.store, id)
if err != nil {
return "", errors.Errorf("layer, image, or container %s does not exist", id)
}
} else {
toLayer = toCtr.LayerID
}
} else {
toLayer = toImage.TopLayer
}
return toLayer, nil
}
func (c *ContainerServer) getLayerParent(layerID string) (string, error) {
layer, err := c.store.Layer(layerID)
if err != nil {
return "", err
}
return layer.Parent, nil
}

12
libkpod/layer/layer.go Normal file
View file

@ -0,0 +1,12 @@
package layer
import cstorage "github.com/containers/storage"
// FullID gets the full id of a layer given a partial id or name
func FullID(store cstorage.Store, id string) (string, error) {
layer, err := store.Layer(id)
if err != nil {
return "", err
}
return layer.ID, nil
}

37
test/kpod_diff.bats Normal file
View file

@ -0,0 +1,37 @@
#/usr/bin/env bats
load helpers
IMAGE="alpine:latest"
ROOT="$TESTDIR/crio"
RUNROOT="$TESTDIR/crio-run"
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT --storage-driver vfs"
function teardown() {
cleanup_test
}
@test "test diff of image and parent" {
run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE
[ "$status" -eq 0 ]
run ${KPOD_BINARY} $KPOD_OPTIONS diff $IMAGE
[ "$status" -eq 0 ]
echo "$output"
run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE
}
@test "test diff on non-existent layer" {
run ${KPOD_BINARY} $KPOD_OPTIONS diff "abc123"
[ "$status" -ne 0 ]
echo "$output"
}
@test "test diff with json output" {
run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE
[ "$status" -eq 0 ]
# run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} diff --json $IMAGE | python -m json.tool"
run ${KPOD_BINARY} $KPOD_OPTIONS diff --json $IMAGE
[ "$status" -eq 0 ]
echo "$output"
run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE
}