Clean up WCOW layers after tests in the correct order
This ensures that we do not trigger assertions inside HCS by tring to call hcsshim.DestroyLayer on the parent of a currently-activated layer. It also deactivates the layers before deletion, to ensure we trigger or avert file-in-use failures due to leftover state from the tests with more detail than 'destroy failed'. Signed-off-by: Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
This commit is contained in:
parent
31a0f92df1
commit
da7d96ba3f
@ -22,11 +22,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim"
|
"github.com/Microsoft/hcsshim"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -257,12 +260,71 @@ func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle,
|
|||||||
return h, e
|
return h, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForceRemoveAll is the same as os.RemoveAll, but uses hcsshim.DestroyLayer in order
|
// ForceRemoveAll is the same as os.RemoveAll, but is aware of io.containerd.snapshotter.v1.windows
|
||||||
// to delete container layers.
|
// and uses hcsshim to unmount and delete container layers contained therein, in the correct order,
|
||||||
|
// when passed a containerd root data directory (i.e. the `--root` directory for containerd).
|
||||||
func ForceRemoveAll(path string) error {
|
func ForceRemoveAll(path string) error {
|
||||||
info := hcsshim.DriverInfo{
|
// snapshots/windows/windows.go init()
|
||||||
HomeDir: filepath.Dir(path),
|
const snapshotPlugin = "io.containerd.snapshotter.v1" + "." + "windows"
|
||||||
|
// snapshots/windows/windows.go NewSnapshotter()
|
||||||
|
snapshotDir := filepath.Join(path, snapshotPlugin, "snapshots")
|
||||||
|
if stat, err := os.Stat(snapshotDir); err == nil && stat.IsDir() {
|
||||||
|
if err := cleanupWCOWLayers(snapshotDir); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to cleanup WCOW layers in %s", snapshotDir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hcsshim.DestroyLayer(info, filepath.Base(path))
|
return os.RemoveAll(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupWCOWLayers(root string) error {
|
||||||
|
// See snapshots/windows/windows.go getSnapshotDir()
|
||||||
|
var layerNums []int
|
||||||
|
if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if path != root && info.IsDir() {
|
||||||
|
if layerNum, err := strconv.Atoi(filepath.Base(path)); err == nil {
|
||||||
|
layerNums = append(layerNums, layerNum)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(sort.Reverse(sort.IntSlice(layerNums)))
|
||||||
|
|
||||||
|
for _, layerNum := range layerNums {
|
||||||
|
if err := cleanupWCOWLayer(filepath.Join(root, strconv.Itoa(layerNum))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupWCOWLayer(layerPath string) error {
|
||||||
|
info := hcsshim.DriverInfo{
|
||||||
|
HomeDir: filepath.Dir(layerPath),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ERROR_DEV_NOT_EXIST is returned if the layer is not currently prepared.
|
||||||
|
if err := hcsshim.UnprepareLayer(info, filepath.Base(layerPath)); err != nil {
|
||||||
|
if hcserror, ok := err.(*hcsshim.HcsError); !ok || hcserror.Err != windows.ERROR_DEV_NOT_EXIST {
|
||||||
|
return errors.Wrapf(err, "failed to unprepare %s", layerPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hcsshim.DeactivateLayer(info, filepath.Base(layerPath)); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to deactivate %s", layerPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hcsshim.DestroyLayer(info, filepath.Base(layerPath)); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to destroy %s", layerPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user