From dd52bfd5f250447d84058291285c9202f30ea56c Mon Sep 17 00:00:00 2001 From: Maksim An Date: Thu, 11 May 2023 13:15:17 -0700 Subject: [PATCH] make sure to close files in dmverity-vhd tool Currently we're not closing output VHD files and read closers when creating layer VHDs with dmverity-vhd tool. Refactor error wrapping. Signed-off-by: Maksim An --- cmd/dmverity-vhd/main.go | 141 ++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/cmd/dmverity-vhd/main.go b/cmd/dmverity-vhd/main.go index 439a750352..f9d84e1581 100644 --- a/cmd/dmverity-vhd/main.go +++ b/cmd/dmverity-vhd/main.go @@ -81,14 +81,14 @@ func fetchImageLayers(ctx *cli.Context) (layers []v1.Layer, err error) { tarballPath := ctx.GlobalString(tarballFlag) ref, err := name.ParseReference(image) if err != nil { - return nil, errors.Wrapf(err, "failed to parse image reference: %s", image) + return nil, fmt.Errorf("failed to parse image reference %s: %w", image, err) } dockerDaemon := ctx.GlobalBool(dockerFlag) // error check to make sure docker and tarball are not both defined if dockerDaemon && tarballPath != "" { - return nil, errors.Errorf("cannot use both docker and tarball for image source") + return nil, errors.New("cannot use both docker and tarball for image source") } // by default, using remote as source @@ -98,7 +98,7 @@ func fetchImageLayers(ctx *cli.Context) (layers []v1.Layer, err error) { 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) + return nil, fmt.Errorf("failed to failed to create a tag to search tarball for %s: %w", image, err) } // if only an image name is provided and not a tag, the default is "latest" img, err = tarball.ImageFromPath(tarballPath, &imageNameAndTag) @@ -113,7 +113,7 @@ func fetchImageLayers(ctx *cli.Context) (layers []v1.Layer, err error) { } authConf, err := auth.Authorization() if err != nil { - return nil, errors.Wrapf(err, "failed to set remote") + return nil, fmt.Errorf("failed to set remote: %w", err) } log.Debug("using basic auth") authOpt := remote.WithAuth(authn.FromConfig(*authConf)) @@ -123,7 +123,7 @@ func fetchImageLayers(ctx *cli.Context) (layers []v1.Layer, err error) { img, err = remote.Image(ref, remoteOpts...) } if err != nil { - return nil, errors.Wrapf(err, "unable to fetch image %q, make sure it exists", image) + return nil, fmt.Errorf("unable to fetch image %q, make sure it exists: %w", image, err) } conf, _ := img.ConfigName() log.Debugf("Image id: %s", conf.String()) @@ -165,68 +165,80 @@ var createVHDCommand = cli.Command{ layers, err := fetchImageLayers(ctx) if err != nil { - return errors.Wrap(err, "failed to fetch image layers") + return fmt.Errorf("failed to fetch image layers: %w", err) } outDir := ctx.String(outputDirFlag) if _, err := os.Stat(outDir); os.IsNotExist(err) { log.Debugf("creating output directory %q", outDir) if err := os.MkdirAll(outDir, 0755); err != nil { - return errors.Wrapf(err, "failed to create output directory %s", outDir) + return fmt.Errorf("failed to create output directory %s: %w", outDir, err) } } log.Debug("creating layer VHDs with dm-verity:") for layerNumber, layer := range layers { - diffID, err := layer.DiffID() - if err != nil { - return errors.Wrap(err, "failed to read layer diff") + log.Debugf("Layer #%d", layerNumber) + if err := createVHD(layer, ctx.String(outputDirFlag), ctx.Bool(hashDeviceVhdFlag)); err != nil { + return err } - log.Debugf("Layer #%d, layer hash: %s", layerNumber, diffID.String()) + } + return nil + }, +} - rc, err := layer.Uncompressed() - if err != nil { - return errors.Wrapf(err, "failed to uncompress layer %s", diffID.String()) - } +func createVHD(layer v1.Layer, outDir string, verityHashDev bool) error { + diffID, err := layer.DiffID() + if err != nil { + return fmt.Errorf("failed to read layer diff: %w", err) + } + log.Debugf("Layer hash: %s", diffID.String()) - vhdPath := filepath.Join(ctx.String(outputDirFlag), diffID.Hex+".vhd") - out, err := os.Create(vhdPath) - if err != nil { - return errors.Wrapf(err, "failed to create layer vhd %s", vhdPath) - } + rc, err := layer.Uncompressed() + if err != nil { + return fmt.Errorf("failed to uncompress layer %s: %w", diffID.String(), err) + } + defer rc.Close() - log.Debug("converting tar to layer VHD") - opts := []tar2ext4.Option{ - tar2ext4.ConvertWhiteout, - tar2ext4.MaximumDiskSize(maxVHDSize), - } - if !ctx.Bool(hashDeviceVhdFlag) { - opts = append(opts, tar2ext4.AppendDMVerity) - } - if err := tar2ext4.Convert(rc, out, opts...); err != nil { - return errors.Wrap(err, "failed to convert tar to ext4") - } - if ctx.Bool(hashDeviceVhdFlag) { - hashDevPath := filepath.Join(ctx.String(outputDirFlag), diffID.Hex+".hash-dev.vhd") - hashDev, err := os.Create(hashDevPath) - if err != nil { - return errors.Wrap(err, "failed to create hash device VHD file") - } - if err := dmverity.ComputeAndWriteHashDevice(out, hashDev); err != nil { - return err - } - if err := tar2ext4.ConvertToVhd(hashDev); err != nil { - return err - } - fmt.Fprintf(os.Stdout, "Layer %d: hash device created at %s\n", layerNumber, hashDevPath) - } - if err := tar2ext4.ConvertToVhd(out); err != nil { - return errors.Wrap(err, "failed to append VHD footer") - } - fmt.Fprintf(os.Stdout, "Layer %d: layer VHD created at %s\n", layerNumber, vhdPath) + vhdPath := filepath.Join(outDir, diffID.Hex+".vhd") + out, err := os.Create(vhdPath) + if err != nil { + return fmt.Errorf("failed to create layer vhd file %s: %w", vhdPath, err) + } + defer out.Close() + + log.Debug("converting tar to layer VHD") + opts := []tar2ext4.Option{ + tar2ext4.ConvertWhiteout, + tar2ext4.MaximumDiskSize(maxVHDSize), + } + if !verityHashDev { + opts = append(opts, tar2ext4.AppendDMVerity) + } + if err := tar2ext4.Convert(rc, out, opts...); err != nil { + return fmt.Errorf("failed to convert tar to ext4: %w", err) + } + if verityHashDev { + hashDevPath := filepath.Join(outDir, diffID.Hex+".hash-dev.vhd") + hashDev, err := os.Create(hashDevPath) + if err != nil { + return fmt.Errorf("failed to create hash device VHD file: %w", err) } - return nil - }, + defer hashDev.Close() + + if err := dmverity.ComputeAndWriteHashDevice(out, hashDev); err != nil { + return err + } + if err := tar2ext4.ConvertToVhd(hashDev); err != nil { + return err + } + fmt.Fprintf(os.Stdout, "hash device created at %s\n", hashDevPath) + } + if err := tar2ext4.ConvertToVhd(out); err != nil { + return fmt.Errorf("failed to append VHD footer: %w", err) + } + fmt.Fprintf(os.Stdout, "Layer VHD created at %s\n", vhdPath) + return nil } var rootHashVHDCommand = cli.Command{ @@ -255,25 +267,34 @@ var rootHashVHDCommand = cli.Command{ layers, err := fetchImageLayers(ctx) if err != nil { - return errors.Wrap(err, "failed to fetch image layers") + return fmt.Errorf("failed to fetch image layers: %w", err) } log.Debugf("%d layers found", len(layers)) - for layerNumber, layer := range layers { - diffID, err := layer.DiffID() + convertFunc := func(layer v1.Layer) (string, error) { + rc, err := layer.Uncompressed() if err != nil { - return errors.Wrap(err, "failed to read layer diff") + return "", err } - log.Debugf("Layer %d. Uncompressed layer hash: %s", layerNumber, diffID.String()) + defer rc.Close() - rc, err := layer.Uncompressed() + hash, err := tar2ext4.ConvertAndComputeRootDigest(rc) if err != nil { - return errors.Wrapf(err, "failed to uncompress layer %s", diffID.String()) + return "", err } + return hash, err + } - hash, err := tar2ext4.ConvertAndComputeRootDigest(rc) + for layerNumber, layer := range layers { + diffID, err := layer.DiffID() + if err != nil { + return fmt.Errorf("failed to read layer diff: %w", err) + } + log.Debugf("Layer %d. Uncompressed layer hash: %s", layerNumber, diffID.String()) + + hash, err := convertFunc(layer) if err != nil { - return errors.Wrap(err, "failed to compute root hash") + return fmt.Errorf("failed to compute root digest: %w", err) } fmt.Fprintf(os.Stdout, "Layer %d\nroot hash: %s\n", layerNumber, hash) }