diff --git a/cmd/dmverity-vhd/README.md b/cmd/dmverity-vhd/README.md index d1955cadc8..330a7e196f 100644 --- a/cmd/dmverity-vhd/README.md +++ b/cmd/dmverity-vhd/README.md @@ -23,11 +23,19 @@ generator. ## Example usage Create VHDs: + ```bash dmverity-vhd create -i alpine:3.12 -o alpine_3_12_layers ``` Compute root hashes: + ```bash dmverity-vhd --docker roothash -i alpine:3.12 ``` + +Compute root hashes with tarball: + +```bash +dmverity-vhd --tarball /path/to/tarball.tar roothash -i alpine:3.12 +``` diff --git a/cmd/dmverity-vhd/main.go b/cmd/dmverity-vhd/main.go index c95fa2dda8..69159d0c84 100644 --- a/cmd/dmverity-vhd/main.go +++ b/cmd/dmverity-vhd/main.go @@ -10,6 +10,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -26,7 +27,8 @@ const ( imageFlag = "image" verboseFlag = "verbose" outputDirFlag = "out-dir" - sourceFlag = "docker" + dockerFlag = "docker" + tarballFlag = "tarball" hashDeviceVhdFlag = "hash-dev-vhd" maxVHDSize = dmverity.RecommendedVHDSizeGB ) @@ -59,9 +61,29 @@ func main() { Usage: "Optional: verbose output", }, cli.BoolFlag{ - Name: sourceFlag + ",d", + Name: dockerFlag + ",d", Usage: "Optional: use local docker daemon", }, + cli.StringFlag{ + Name: tarballFlag + ",t", + Usage: "Optional: path to tarball containing image info", + }, + } + + // error check to see if the `docker` and `tarball` flags are both being used + // without having access to the `cli.Context` struct + localDockerUsed := false + tarballUsed := false + for i := 0; i < len(os.Args); i++ { + if os.Args[i] == "-d" || os.Args[i] == "-"+dockerFlag { + localDockerUsed = true + } else if os.Args[i] == "-t" || os.Args[i] == "-"+tarballFlag { + tarballUsed = true + } + } + if localDockerUsed && tarballUsed { + _, _ = fmt.Fprintln(os.Stderr, "cannot use both docker and tarball for image source") + os.Exit(1) } if err := app.Run(os.Args); err != nil { @@ -72,16 +94,26 @@ func main() { func fetchImageLayers(ctx *cli.Context) (layers []v1.Layer, err error) { image := ctx.String(imageFlag) + tarballPath := ctx.GlobalString(tarballFlag) ref, err := name.ParseReference(image) if err != nil { return nil, errors.Wrapf(err, "failed to parse image reference: %s", image) } - local := ctx.GlobalBool(sourceFlag) + dockerDaemon := ctx.GlobalBool(dockerFlag) // by default, using remote as source var img v1.Image - if local { + if tarballPath != "" { + // create a tag and search the tarball for the image specified + var imageNameAndTag name.Tag + imageNameAndTag, err = name.NewTag(image) + if err != nil { + return nil, errors.Wrapf(err, "failed to failed to create a tag to search tarball for: %s", image) + } + // if only an image name is provided and not a tag, the default is "latest" + img, err = tarball.ImageFromPath(tarballPath, &imageNameAndTag) + } else if dockerDaemon { img, err = daemon.Image(ref) } else { var remoteOpts []remote.Option