Extend driver.ListLayers()
Implement ListLayers() for the aufs, btrfs, and devicemapper drivers, along with a unit test for them. Stop filtering out directories with names that aren't 64-hex chars in vfs and overlay ListLayers() implementations, which is more a convention than a hard rule. Have layerStore.Wipe() try to remove remaining listed layers after it removes the layers that the layerStore knew of. Close() a dangling ReadCloser in NaiveCreateFromTemplate. Switch from using plain defer to using t.Cleanup() to handle deleting layers that tests create, have the addManyLayers() test function do so as well. Remove vfs.CopyDir, which near as I can tell isn't referenced anywhere. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
4cc5edf4f2
commit
d10c03bc3d
2
Makefile
2
Makefile
|
|
@ -66,7 +66,7 @@ docs: install.tools ## build the docs on the host
|
|||
local-test: local-binary local-test-unit local-test-integration ## build the binaries and run the tests
|
||||
|
||||
local-test-unit test-unit: local-binary ## run the unit tests on the host (requires\nsuperuser privileges)
|
||||
@$(GO) test $(MOD_VENDOR) $(BUILDFLAGS) $(TESTFLAGS) $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
|
||||
@$(GO) test -count 1 $(MOD_VENDOR) $(BUILDFLAGS) $(TESTFLAGS) $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
|
||||
|
||||
local-test-integration test-integration: local-binary ## run the integration tests on the host (requires\nsuperuser privileges)
|
||||
@cd tests; ./test_runner.bash
|
||||
|
|
|
|||
|
|
@ -251,9 +251,21 @@ func (a *Driver) Exists(id string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// List layers (not including additional image stores)
|
||||
// ListLayers() returns all of the layers known to the driver.
|
||||
func (a *Driver) ListLayers() ([]string, error) {
|
||||
return nil, graphdriver.ErrNotSupported
|
||||
diffsDir := filepath.Join(a.rootPath(), "diff")
|
||||
entries, err := os.ReadDir(diffsDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]string, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
results = append(results, entry.Name())
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// AdditionalImageStores returns additional image stores supported by the driver
|
||||
|
|
|
|||
|
|
@ -824,3 +824,7 @@ func TestAufsCreateFromTemplate(t *testing.T) {
|
|||
func TestAufsEcho(t *testing.T) {
|
||||
graphtest.DriverTestEcho(t, "aufs")
|
||||
}
|
||||
|
||||
func TestAufsListLayers(t *testing.T) {
|
||||
graphtest.DriverTestListLayers(t, "aufs")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil {
|
||||
if err := idtools.MkdirAllAs(filepath.Join(home, "subvolumes"), 0700, rootUID, rootGID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) {
|
|||
case "btrfs.mountopt":
|
||||
return options, userDiskQuota, fmt.Errorf("btrfs driver does not support mount options")
|
||||
default:
|
||||
return options, userDiskQuota, fmt.Errorf("unknown option %s", key)
|
||||
return options, userDiskQuota, fmt.Errorf("unknown option %s (%q)", key, option)
|
||||
}
|
||||
}
|
||||
return options, userDiskQuota, nil
|
||||
|
|
@ -479,8 +479,8 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
|
|||
|
||||
// Create the filesystem with given id.
|
||||
func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
||||
quotas := path.Join(d.home, "quotas")
|
||||
subvolumes := path.Join(d.home, "subvolumes")
|
||||
quotas := d.quotasDir()
|
||||
subvolumes := d.subvolumesDir()
|
||||
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -560,7 +560,7 @@ func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) e
|
|||
}
|
||||
driver.options.size = uint64(size)
|
||||
default:
|
||||
return fmt.Errorf("unknown option %s", key)
|
||||
return fmt.Errorf("unknown option %s (%q)", key, storageOpt)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -679,9 +679,21 @@ func (d *Driver) Exists(id string) bool {
|
|||
return err == nil
|
||||
}
|
||||
|
||||
// List layers (not including additional image stores)
|
||||
// List all of the layers known to the driver.
|
||||
func (d *Driver) ListLayers() ([]string, error) {
|
||||
return nil, graphdriver.ErrNotSupported
|
||||
subvolumesDir := filepath.Join(d.home, "subvolumes")
|
||||
entries, err := os.ReadDir(subvolumesDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]string, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
results = append(results, entry.Name())
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// AdditionalImageStores returns additional image stores supported by the driver
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ func TestBtrfsEcho(t *testing.T) {
|
|||
graphtest.DriverTestEcho(t, "btrfs")
|
||||
}
|
||||
|
||||
func TestBtrfsListLayers(t *testing.T) {
|
||||
graphtest.DriverTestListLayers(t, "btrfs")
|
||||
}
|
||||
|
||||
func TestBtrfsTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1001,6 +1001,10 @@ func (devices *DeviceSet) verifyBaseDeviceUUIDFS(baseInfo *devInfo) error {
|
|||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if devices.filesystem == "" {
|
||||
devices.filesystem = determineDefaultFS()
|
||||
}
|
||||
|
||||
if err := devices.activateDeviceIfNeeded(baseInfo, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1707,6 +1711,9 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
|
|||
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := idtools.MkdirAs(filepath.Join(devices.root, "mnt"), 0700, uid, gid); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return err
|
||||
}
|
||||
|
||||
prevSetupConfig, err := readLVMConfig(devices.root)
|
||||
if err != nil {
|
||||
|
|
@ -2317,7 +2324,7 @@ func (devices *DeviceSet) Shutdown(home string) error {
|
|||
info.lock.Lock()
|
||||
devices.Lock()
|
||||
if err := devices.deactivateDevice(info); err != nil {
|
||||
logrus.Debugf("devmapper: Shutdown deactivate base , error: %s", err)
|
||||
logrus.Debugf("devmapper: Shutdown deactivate base, error: %s", err)
|
||||
}
|
||||
devices.Unlock()
|
||||
info.lock.Unlock()
|
||||
|
|
@ -2326,7 +2333,7 @@ func (devices *DeviceSet) Shutdown(home string) error {
|
|||
devices.Lock()
|
||||
if devices.thinPoolDevice == "" {
|
||||
if err := devices.deactivatePool(); err != nil {
|
||||
logrus.Debugf("devmapper: Shutdown deactivate pool , error: %s", err)
|
||||
logrus.Debugf("devmapper: Shutdown deactivate pool, error: %s", err)
|
||||
}
|
||||
}
|
||||
devices.Unlock()
|
||||
|
|
@ -2483,6 +2490,26 @@ func (devices *DeviceSet) List() []string {
|
|||
return ids
|
||||
}
|
||||
|
||||
// ListLayers returns a list of device IDs, omitting the ""/"base" device and
|
||||
// any which have been marked as deleted.
|
||||
func (devices *DeviceSet) ListLayers() ([]string, error) {
|
||||
if err := devices.cleanupDeletedDevices(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
ids := make([]string, 0, len(devices.Devices))
|
||||
for k, d := range devices.Devices {
|
||||
if k == "" || d.Deleted {
|
||||
continue
|
||||
}
|
||||
ids = append(ids, k)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
|
||||
var params string
|
||||
_, sizeInSectors, _, params, err = devicemapper.GetStatus(devName)
|
||||
|
|
|
|||
|
|
@ -91,14 +91,18 @@ func TestDevmapperCreateFromTemplate(t *testing.T) {
|
|||
graphtest.DriverTestCreateFromTemplate(t, "devicemapper", "test=1")
|
||||
}
|
||||
|
||||
func TestDevmapperTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
||||
func TestDevmapperEcho(t *testing.T) {
|
||||
graphtest.DriverTestEcho(t, "devicemapper", "test=1")
|
||||
}
|
||||
|
||||
func TestDevmapperListLayers(t *testing.T) {
|
||||
graphtest.DriverTestListLayers(t, "devicemapper", "test=1")
|
||||
}
|
||||
|
||||
func TestDevmapperTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
||||
func TestDevmapperReduceLoopBackSize(t *testing.T) {
|
||||
tenMB := int64(10 * 1024 * 1024)
|
||||
testChangeLoopBackSize(t, -tenMB, defaultDataLoopbackSize, defaultMetaDataLoopbackSize)
|
||||
|
|
@ -130,7 +134,7 @@ func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataS
|
|||
}
|
||||
driver = d.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
|
||||
if s := driver.DeviceSet.Status(); s.Data.Total != uint64(expectDataSize) || s.Metadata.Total != uint64(expectMetaDataSize) {
|
||||
t.Fatal("data or metadata loop back size is incorrect")
|
||||
t.Fatalf("data or metadata loop back size is incorrect (data actual/expected=%d/%d, metadata actual/expected = %d/%d)", s.Data.Total, expectDataSize, s.Metadata.Total, expectMetaDataSize)
|
||||
}
|
||||
if err := driver.Cleanup(); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
|||
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
|
||||
locker: locker.New(),
|
||||
}
|
||||
|
||||
return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
|
||||
}
|
||||
|
||||
|
|
@ -267,11 +266,6 @@ func (d *Driver) Exists(id string) bool {
|
|||
return d.DeviceSet.HasDevice(id)
|
||||
}
|
||||
|
||||
// List layers (not including additional image stores)
|
||||
func (d *Driver) ListLayers() ([]string, error) {
|
||||
return nil, graphdriver.ErrNotSupported
|
||||
}
|
||||
|
||||
// AdditionalImageStores returns additional image stores supported by the driver
|
||||
func (d *Driver) AdditionalImageStores() []string {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ func DriverBenchDeepLayerDiff(b *testing.B, layerCount int, drivername string, d
|
|||
b.Fatal(err)
|
||||
}
|
||||
|
||||
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||
topLayer, err := addManyLayers(b, driver, base, layerCount)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
@ -232,7 +232,7 @@ func DriverBenchDeepLayerRead(b *testing.B, layerCount int, drivername string, d
|
|||
b.Fatal(err)
|
||||
}
|
||||
|
||||
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||
topLayer, err := addManyLayers(b, driver, base, layerCount)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
graphdriver "github.com/containers/storage/drivers"
|
||||
|
|
@ -27,8 +28,12 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultPerms = os.FileMode(0555)
|
||||
modifiedPerms = os.FileMode(0711)
|
||||
defaultPerms = os.FileMode(0o555)
|
||||
modifiedPerms = os.FileMode(0o711)
|
||||
defaultSubdirPerms = os.FileMode(0o705)
|
||||
defaultSubdirOwner = 1
|
||||
defaultSubdirGroup = 2
|
||||
defaultFilePerms = os.FileMode(0o222)
|
||||
)
|
||||
|
||||
// Driver conforms to graphdriver.Driver interface and
|
||||
|
|
@ -92,14 +97,12 @@ func PutDriver(t testing.TB) {
|
|||
// DriverTestCreateEmpty creates a new image and verifies it is empty and the right metadata
|
||||
func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
err := driver.Create("empty", "", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("empty"))
|
||||
}()
|
||||
t.Cleanup(func() { removeLayer(t, driver, "empty") })
|
||||
|
||||
if !driver.Exists("empty") {
|
||||
t.Fatal("Newly created image doesn't exist")
|
||||
|
|
@ -121,30 +124,24 @@ func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...str
|
|||
// DriverTestCreateBase create a base driver and verify.
|
||||
func DriverTestCreateBase(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
createBase(t, driver, "Base1")
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("Base1"))
|
||||
}()
|
||||
verifyBase(t, driver, "Base1", defaultPerms)
|
||||
}
|
||||
|
||||
// DriverTestCreateSnap Create a driver and snap and verify.
|
||||
func DriverTestCreateSnap(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
createBase(t, driver, "Base2")
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("Base2"))
|
||||
}()
|
||||
|
||||
err := driver.Create("Snap2", "Base2", nil)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("Snap2"))
|
||||
}()
|
||||
t.Cleanup(func() { removeLayer(t, driver, "Snap2") })
|
||||
|
||||
verifyBase(t, driver, "Snap2", defaultPerms)
|
||||
|
||||
|
|
@ -156,9 +153,7 @@ func DriverTestCreateSnap(t testing.TB, drivername string, driverOptions ...stri
|
|||
|
||||
err = driver.Create("SecondSnap", "Snap2", nil)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("SecondSnap"))
|
||||
}()
|
||||
t.Cleanup(func() { removeLayer(t, driver, "SecondSnap") })
|
||||
|
||||
verifyBase(t, driver, "SecondSnap", modifiedPerms)
|
||||
}
|
||||
|
|
@ -167,18 +162,15 @@ func DriverTestCreateSnap(t testing.TB, drivername string, driverOptions ...stri
|
|||
// contents.
|
||||
func DriverTestCreateFromTemplate(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
createBase(t, driver, "Base3")
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("Base3"))
|
||||
}()
|
||||
verifyBase(t, driver, "Base3", defaultPerms)
|
||||
|
||||
err := driver.Create("Snap3", "Base3", nil)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("Snap3"))
|
||||
}()
|
||||
t.Cleanup(func() { removeLayer(t, driver, "Snap3") })
|
||||
|
||||
content := []byte("test content")
|
||||
if err := addFile(driver, "Snap3", "testfile.txt", content); err != nil {
|
||||
|
|
@ -187,15 +179,10 @@ func DriverTestCreateFromTemplate(t testing.TB, drivername string, driverOptions
|
|||
|
||||
err = driver.CreateFromTemplate("FromTemplate", "Snap3", nil, "Base3", nil, nil, true)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("FromTemplate"))
|
||||
}()
|
||||
|
||||
t.Cleanup(func() { removeLayer(t, driver, "FromTemplate") })
|
||||
err = driver.CreateFromTemplate("ROFromTemplate", "Snap3", nil, "Base3", nil, nil, false)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, driver.Remove("ROFromTemplate"))
|
||||
}()
|
||||
t.Cleanup(func() { removeLayer(t, driver, "ROFromTemplate") })
|
||||
|
||||
noChanges := []archive.Change{}
|
||||
|
||||
|
|
@ -260,19 +247,21 @@ func DriverTestCreateFromTemplate(t testing.TB, drivername string, driverOptions
|
|||
// DriverTestDeepLayerRead reads a file from a lower layer under a given number of layers
|
||||
func DriverTestDeepLayerRead(t testing.TB, layerCount int, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
base := stringid.GenerateRandomID()
|
||||
if err := driver.Create(base, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, base) })
|
||||
|
||||
content := []byte("test content")
|
||||
if err := addFile(driver, base, "testfile.txt", content); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
topLayer, err := addManyLayers(driver, base, layerCount)
|
||||
topLayer, err := addManyLayers(t, driver, base, layerCount)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -290,6 +279,7 @@ func DriverTestDeepLayerRead(t testing.TB, layerCount int, drivername string, dr
|
|||
// DriverTestDiffApply tests diffing and applying produces the same layer
|
||||
func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
base := stringid.GenerateRandomID()
|
||||
upper := stringid.GenerateRandomID()
|
||||
|
|
@ -300,6 +290,7 @@ func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverO
|
|||
if err := driver.Create(base, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, base) })
|
||||
|
||||
if err := addManyFiles(driver, base, fileCount, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -316,6 +307,7 @@ func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverO
|
|||
if err := driver.Create(upper, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, upper) })
|
||||
|
||||
if err := addManyFiles(driver, upper, fileCount, 6); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -334,6 +326,7 @@ func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverO
|
|||
if err := driver.Create(diff, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, diff) })
|
||||
|
||||
if err := checkManyFiles(driver, diff, fileCount, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -381,12 +374,15 @@ func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverO
|
|||
// DriverTestChanges tests computed changes on a layer matches changes made
|
||||
func DriverTestChanges(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
base := stringid.GenerateRandomID()
|
||||
upper := stringid.GenerateRandomID()
|
||||
|
||||
if err := driver.Create(base, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, base) })
|
||||
|
||||
if err := addManyFiles(driver, base, 20, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -395,6 +391,7 @@ func DriverTestChanges(t testing.TB, drivername string, driverOptions ...string)
|
|||
if err := driver.Create(upper, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, upper) })
|
||||
|
||||
expectedChanges, err := changeManyFiles(driver, upper, 20, 6)
|
||||
if err != nil {
|
||||
|
|
@ -425,15 +422,19 @@ func writeRandomFile(path string, size uint64) error {
|
|||
// DriverTestSetQuota Create a driver and test setting quota.
|
||||
func DriverTestSetQuota(t *testing.T, drivername string) {
|
||||
driver := GetDriver(t, drivername)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
|
||||
createBase(t, driver, "Base4")
|
||||
verifyBase(t, driver, "Base4", defaultPerms)
|
||||
|
||||
createOpts := &graphdriver.CreateOpts{}
|
||||
createOpts.StorageOpt = make(map[string]string, 1)
|
||||
createOpts.StorageOpt["size"] = "50M"
|
||||
if err := driver.Create("quotaTest", "Base4", createOpts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, "quotaTest") })
|
||||
|
||||
mountPath, err := driver.Get("quotaTest", graphdriver.MountOpts{})
|
||||
if err != nil {
|
||||
|
|
@ -454,6 +455,7 @@ func DriverTestSetQuota(t *testing.T, drivername string) {
|
|||
// DriverTestEcho tests that we can diff a layer correctly, focusing on trouble spots that NaiveDiff doesn't have
|
||||
func DriverTestEcho(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
var err error
|
||||
var root string
|
||||
|
|
@ -464,17 +466,19 @@ func DriverTestEcho(t testing.TB, drivername string, driverOptions ...string) {
|
|||
second := stringid.GenerateRandomID()
|
||||
third := stringid.GenerateRandomID()
|
||||
|
||||
if err := driver.Create(base, "", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
createBase(t, driver, base)
|
||||
verifyBase(t, driver, base, defaultPerms)
|
||||
|
||||
if root, err = driver.Get(base, graphdriver.MountOpts{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedChanges := []archive.Change{
|
||||
{Kind: archive.ChangeAdd, Path: "/a file"},
|
||||
{Kind: archive.ChangeAdd, Path: "/a subdir"},
|
||||
}
|
||||
paths := []string{}
|
||||
path := "/"
|
||||
expectedChanges := []archive.Change{}
|
||||
for i := 0; i < components-1; i++ {
|
||||
path = filepath.Join(path, fmt.Sprintf("subdir%d", i+1))
|
||||
paths = append(paths, path)
|
||||
|
|
@ -502,6 +506,7 @@ func DriverTestEcho(t testing.TB, drivername string, driverOptions ...string) {
|
|||
if err := driver.Create(second, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, second) })
|
||||
|
||||
if root, err = driver.Get(second, graphdriver.MountOpts{}); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -528,6 +533,7 @@ func DriverTestEcho(t testing.TB, drivername string, driverOptions ...string) {
|
|||
if err = driver.Create(third, second, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, third) })
|
||||
|
||||
if root, err = driver.Get(third, graphdriver.MountOpts{}); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -571,3 +577,45 @@ func DriverTestEcho(t testing.TB, drivername string, driverOptions ...string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DriverTestListLayers makes sure ListLayers() returns what we expected, nothing more, nothing less
|
||||
func DriverTestListLayers(t testing.TB, drivername string, driverOptions ...string) {
|
||||
driver := GetDriver(t, drivername, driverOptions...)
|
||||
require.NotNil(t, drv.Driver, "initializing driver")
|
||||
defer PutDriver(t)
|
||||
base := stringid.GenerateRandomID()
|
||||
mid := stringid.GenerateRandomID()
|
||||
upper := stringid.GenerateRandomID()
|
||||
|
||||
createBase(t, driver, base)
|
||||
verifyBase(t, driver, base, defaultPerms)
|
||||
|
||||
if err := addManyFiles(driver, base, 20, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.Create(mid, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, mid) })
|
||||
|
||||
if err := addManyFiles(driver, mid, 20, 3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.Create(upper, mid, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, driver, upper) })
|
||||
|
||||
list, err := driver.ListLayers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sort.Strings(list)
|
||||
|
||||
expected := []string{base, mid, upper}
|
||||
sort.Strings(expected)
|
||||
|
||||
assert.Equal(t, expected, list, "listed layers were not exactly what we created")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
graphdriver "github.com/containers/storage/drivers"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func randomContent(size int, seed int64) []byte {
|
||||
|
|
@ -282,13 +284,14 @@ func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func addManyLayers(drv graphdriver.Driver, baseLayer string, count int) (string, error) {
|
||||
func addManyLayers(t testing.TB, drv graphdriver.Driver, baseLayer string, count int) (string, error) {
|
||||
lastLayer := baseLayer
|
||||
for i := 1; i <= count; i++ {
|
||||
nextLayer := stringid.GenerateRandomID()
|
||||
if err := drv.Create(nextLayer, lastLayer, nil); err != nil {
|
||||
return "", err
|
||||
}
|
||||
t.Cleanup(func() { removeLayer(t, drv, nextLayer) })
|
||||
if err := addLayerFiles(drv, nextLayer, lastLayer, i); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -351,3 +354,9 @@ func readDir(dir string) ([]os.DirEntry, error) {
|
|||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// removeLayer tries to remove the layer
|
||||
func removeLayer(t testing.TB, driver graphdriver.Driver, name string) {
|
||||
err := driver.Remove(name)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,17 +39,18 @@ func createBase(t testing.TB, driver graphdriver.Driver, name string) {
|
|||
|
||||
err := driver.CreateReadWrite(name, "", nil)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { removeLayer(t, driver, name) })
|
||||
|
||||
dir, err := driver.Get(name, graphdriver.MountOpts{})
|
||||
require.NoError(t, err)
|
||||
defer driver.Put(name)
|
||||
|
||||
subdir := path.Join(dir, "a subdir")
|
||||
require.NoError(t, os.Mkdir(subdir, 0705|os.ModeSticky))
|
||||
require.NoError(t, os.Chown(subdir, 1, 2))
|
||||
require.NoError(t, os.Mkdir(subdir, defaultSubdirPerms|os.ModeSticky))
|
||||
require.NoError(t, os.Chown(subdir, defaultSubdirOwner, defaultSubdirGroup))
|
||||
|
||||
file := path.Join(dir, "a file")
|
||||
err = os.WriteFile(file, []byte("Some data"), 0222|os.ModeSetuid)
|
||||
err = os.WriteFile(file, []byte("Some data"), defaultFilePerms|os.ModeSetuid)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
@ -61,10 +62,10 @@ func verifyBase(t testing.TB, driver graphdriver.Driver, name string, defaultPer
|
|||
verifyFile(t, dir, defaultPerm|os.ModeDir, 0, 0)
|
||||
|
||||
subdir := path.Join(dir, "a subdir")
|
||||
verifyFile(t, subdir, 0705|os.ModeDir|os.ModeSticky, 1, 2)
|
||||
verifyFile(t, subdir, defaultSubdirPerms|os.ModeDir|os.ModeSticky, defaultSubdirOwner, defaultSubdirGroup)
|
||||
|
||||
file := path.Join(dir, "a file")
|
||||
verifyFile(t, file, 0222|os.ModeSetuid, 0, 0)
|
||||
verifyFile(t, file, defaultFilePerms|os.ModeSetuid, 0, 0)
|
||||
|
||||
files, err := readDir(dir)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import (
|
|||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/containers/storage/pkg/mount"
|
||||
"github.com/containers/storage/pkg/parsers"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
units "github.com/docker/go-units"
|
||||
|
|
@ -47,7 +46,9 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultPerms = os.FileMode(0555)
|
||||
defaultPerms = os.FileMode(0555)
|
||||
selinuxLabelTest = "system_u:object_r:container_file_t:s0"
|
||||
mountProgramFlagFile = ".has-mount-program"
|
||||
)
|
||||
|
||||
// This backend uses the overlay union filesystem for containers
|
||||
|
|
@ -78,9 +79,10 @@ const (
|
|||
// that mounts do not fail due to length.
|
||||
|
||||
const (
|
||||
linkDir = "l"
|
||||
lowerFile = "lower"
|
||||
maxDepth = 500
|
||||
linkDir = "l"
|
||||
stagingDir = "staging"
|
||||
lowerFile = "lower"
|
||||
maxDepth = 500
|
||||
|
||||
// idLength represents the number of random characters
|
||||
// which can be used to create the unique link identifier
|
||||
|
|
@ -124,7 +126,6 @@ type Driver struct {
|
|||
}
|
||||
|
||||
type additionalLayerStore struct {
|
||||
|
||||
// path is the directory where this store is available on the host.
|
||||
path string
|
||||
|
||||
|
|
@ -175,7 +176,7 @@ func hasVolatileOption(opts []string) bool {
|
|||
}
|
||||
|
||||
func getMountProgramFlagFile(path string) string {
|
||||
return filepath.Join(path, ".has-mount-program")
|
||||
return filepath.Join(path, mountProgramFlagFile)
|
||||
}
|
||||
|
||||
func checkSupportVolatile(home, runhome string) (bool, error) {
|
||||
|
|
@ -958,7 +959,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
|
|||
return err
|
||||
}
|
||||
if parent != "" {
|
||||
st, err := system.Stat(d.dir(parent))
|
||||
st, err := system.Stat(filepath.Join(d.dir(parent), "diff"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1725,20 +1726,23 @@ func (d *Driver) ListLayers() ([]string, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
layers := make([]string, 0)
|
||||
|
||||
for _, entry := range entries {
|
||||
id := entry.Name()
|
||||
// Does it look like a datadir directory?
|
||||
if !entry.IsDir() || stringid.ValidateID(id) != nil {
|
||||
switch id {
|
||||
case linkDir, stagingDir, quota.BackingFsBlockDeviceLink, mountProgramFlagFile:
|
||||
// expected, but not a layer. skip it
|
||||
continue
|
||||
default:
|
||||
// Does it look like a datadir directory?
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
layers = append(layers, id)
|
||||
}
|
||||
|
||||
layers = append(layers, id)
|
||||
}
|
||||
|
||||
return layers, err
|
||||
return layers, nil
|
||||
}
|
||||
|
||||
// isParent returns if the passed in parent is the direct parent of the passed in layer
|
||||
|
|
@ -1795,7 +1799,7 @@ func (g *overlayFileGetter) Close() error {
|
|||
}
|
||||
|
||||
func (d *Driver) getStagingDir() string {
|
||||
return filepath.Join(d.home, "staging")
|
||||
return filepath.Join(d.home, stagingDir)
|
||||
}
|
||||
|
||||
// DiffGetter returns a FileGetCloser that can read files from the directory that
|
||||
|
|
|
|||
|
|
@ -67,14 +67,18 @@ func TestOverlayChanges(t *testing.T) {
|
|||
graphtest.DriverTestChanges(t, driverName)
|
||||
}
|
||||
|
||||
func TestOverlayTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
||||
func TestOverlayEcho(t *testing.T) {
|
||||
graphtest.DriverTestEcho(t, driverName)
|
||||
}
|
||||
|
||||
func TestOverlayListLayers(t *testing.T) {
|
||||
graphtest.DriverTestListLayers(t, driverName)
|
||||
}
|
||||
|
||||
func TestOverlayTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
||||
// Benchmarks should always setup new driver
|
||||
|
||||
func BenchmarkExists(b *testing.B) {
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ import (
|
|||
|
||||
const projectIDsAllocatedPerQuotaHome = 10000
|
||||
|
||||
// BackingFsBlockDeviceLink is the name of a file that we place in
|
||||
// the home directory of a driver that uses this package.
|
||||
const BackingFsBlockDeviceLink = "backingFsBlockDev"
|
||||
|
||||
// Quota limit params - currently we only control blocks hard limit and inodes
|
||||
type Quota struct {
|
||||
Size uint64
|
||||
|
|
@ -421,7 +425,7 @@ func makeBackingFsDev(home string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
backingFsBlockDev := path.Join(home, "backingFsBlockDev")
|
||||
backingFsBlockDev := path.Join(home, BackingFsBlockDeviceLink)
|
||||
backingFsBlockDevTmp := backingFsBlockDev + ".tmp"
|
||||
// Re-create just in case someone copied the home directory over to a new device
|
||||
if err := unix.Mknod(backingFsBlockDevTmp, unix.S_IFBLK|0600, int(stat.Dev)); err != nil {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMa
|
|||
}
|
||||
return err
|
||||
}
|
||||
defer diff.Close()
|
||||
|
||||
applyOptions := ApplyDiffOpts{
|
||||
Diff: diff,
|
||||
|
|
|
|||
|
|
@ -14,18 +14,12 @@ import (
|
|||
"github.com/containers/storage/pkg/directory"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/containers/storage/pkg/parsers"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vbatts/tar-split/tar/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
// CopyDir defines the copy method to use.
|
||||
CopyDir = dirCopy
|
||||
)
|
||||
|
||||
const defaultPerms = os.FileMode(0555)
|
||||
|
||||
func init() {
|
||||
|
|
@ -42,11 +36,10 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
|||
}
|
||||
|
||||
rootIDs := d.idMappings.RootPair()
|
||||
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(filepath.Join(home, "dir"), 0700, rootIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, option := range options.DriverOptions {
|
||||
|
||||
key, val, err := parsers.ParseKeyValueOpt(option)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -268,7 +261,7 @@ func (d *Driver) Exists(id string) bool {
|
|||
|
||||
// List layers (not including additional image stores)
|
||||
func (d *Driver) ListLayers() ([]string, error) {
|
||||
entries, err := os.ReadDir(d.homes[0])
|
||||
entries, err := os.ReadDir(filepath.Join(d.homes[0], "dir"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -278,7 +271,7 @@ func (d *Driver) ListLayers() ([]string, error) {
|
|||
for _, entry := range entries {
|
||||
id := entry.Name()
|
||||
// Does it look like a datadir directory?
|
||||
if !entry.IsDir() || stringid.ValidateID(id) != nil {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ func TestVfsCreateFromTemplate(t *testing.T) {
|
|||
graphtest.DriverTestCreateFromTemplate(t, "vfs")
|
||||
}
|
||||
|
||||
func TestVfsTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
||||
func TestVfsDiffApply100Files(t *testing.T) {
|
||||
graphtest.DriverTestDiffApply(t, 100, "vfs")
|
||||
}
|
||||
|
|
@ -52,3 +48,11 @@ func TestVfsChanges(t *testing.T) {
|
|||
func TestVfsEcho(t *testing.T) {
|
||||
graphtest.DriverTestEcho(t, "vfs")
|
||||
}
|
||||
|
||||
func TestVfsListLayers(t *testing.T) {
|
||||
graphtest.DriverTestListLayers(t, "vfs")
|
||||
}
|
||||
|
||||
func TestVfsTeardown(t *testing.T) {
|
||||
graphtest.PutDriver(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -409,7 +409,6 @@ func (d *Driver) Remove(id string) error {
|
|||
|
||||
// Get returns the mountpoint for the given id after creating the target directories if necessary.
|
||||
func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) {
|
||||
|
||||
mountpoint := d.mountPath(id)
|
||||
if count := d.ctr.Increment(mountpoint); count > 1 {
|
||||
return mountpoint, nil
|
||||
|
|
@ -506,7 +505,9 @@ func (d *Driver) Exists(id string) bool {
|
|||
return d.filesystemsCache[d.zfsPath(id)]
|
||||
}
|
||||
|
||||
// List layers (not including additional image stores)
|
||||
// List layers (not including additional image stores). Our layers aren't all
|
||||
// dependent on a single well-known dataset, so we can't reliably tell which
|
||||
// datasets are ours and which ones just look like they could be ours.
|
||||
func (d *Driver) ListLayers() ([]string, error) {
|
||||
return nil, graphdriver.ErrNotSupported
|
||||
}
|
||||
|
|
|
|||
12
layers.go
12
layers.go
|
|
@ -1922,6 +1922,18 @@ func (r *layerStore) Wipe() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
ids, err := r.driver.ListLayers()
|
||||
if err != nil {
|
||||
if !errors.Is(err, drivers.ErrNotSupported) {
|
||||
return err
|
||||
}
|
||||
ids = nil
|
||||
}
|
||||
for _, id := range ids {
|
||||
if err := r.driver.Remove(id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue