Skip to content

Commit 77df1da

Browse files
committed
exporter: add tests for a directory with an idmap error
this test demonstrates the bug called out in tonistiigi/fsutil#203 Currently, if a directory's UID can't be mapped to the host, buildkit will export an invalid tarball. Signed-off-by: Nick Santos <nick.santos@docker.com>
1 parent 1e403a7 commit 77df1da

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

exporter/local/fs_test.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package local
2+
3+
import (
4+
"context"
5+
iofs "io/fs"
6+
"os"
7+
"path/filepath"
8+
"runtime"
9+
"testing"
10+
"time"
11+
12+
"github.com/containerd/containerd/content/local"
13+
"github.com/containerd/containerd/diff/apply"
14+
"github.com/containerd/containerd/diff/walking"
15+
ctdmetadata "github.com/containerd/containerd/metadata"
16+
"github.com/containerd/containerd/namespaces"
17+
"github.com/containerd/containerd/snapshots"
18+
"github.com/containerd/containerd/snapshots/native"
19+
"github.com/docker/docker/pkg/idtools"
20+
"github.com/moby/buildkit/cache"
21+
"github.com/moby/buildkit/cache/metadata"
22+
"github.com/moby/buildkit/snapshot"
23+
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
24+
"github.com/moby/buildkit/util/leaseutil"
25+
"github.com/moby/buildkit/util/winlayers"
26+
"github.com/pkg/errors"
27+
"github.com/stretchr/testify/require"
28+
bolt "go.etcd.io/bbolt"
29+
)
30+
31+
func TestCreateFS_DirMissingFromIDMap(t *testing.T) {
32+
if runtime.GOOS == "windows" {
33+
// The chown doesn't work quite the same on Windows, so skip this test.
34+
t.Skip("Skipping test on Windows")
35+
}
36+
37+
idmap := &idtools.IdentityMapping{
38+
UIDMaps: []idtools.IDMap{
39+
{ContainerID: 0, HostID: 0, Size: 1},
40+
},
41+
GIDMaps: []idtools.IDMap{
42+
{ContainerID: 0, HostID: 0, Size: 1},
43+
},
44+
}
45+
46+
ctx := namespaces.WithNamespace(context.Background(), "buildkit-test")
47+
cm, err := newCacheManager(ctx, t, idmap)
48+
require.NoError(t, err)
49+
sessionID := "sessionID"
50+
51+
active, err := cm.New(ctx, nil, nil, cache.CachePolicyRetain)
52+
require.NoError(t, err)
53+
54+
m, err := active.Mount(ctx, false, nil)
55+
require.NoError(t, err)
56+
57+
lm := snapshot.LocalMounter(m)
58+
target, err := lm.Mount()
59+
require.NoError(t, err)
60+
61+
_ = os.MkdirAll(filepath.Join(target, "dir"), 0755)
62+
63+
f, err := os.Create(filepath.Join(target, "dir", "test.txt"))
64+
require.NoError(t, err)
65+
_ = f.Close()
66+
67+
_ = os.MkdirAll(filepath.Join(target, "unmapped-dir"), 0755)
68+
os.Chown(filepath.Join(target, "unmapped-dir"), 1001, 1001)
69+
70+
f, err = os.Create(filepath.Join(target, "unmapped-dir", "test.txt"))
71+
require.NoError(t, err)
72+
_ = f.Close()
73+
74+
lm.Unmount()
75+
76+
snap, err := active.Commit(ctx)
77+
require.NoError(t, err)
78+
79+
activeRef, err := cm.Get(ctx, snap.ID(), nil)
80+
require.NoError(t, err)
81+
82+
fs, _, err := CreateFS(ctx, sessionID, "k???", activeRef, nil, time.Now(), CreateFSOpts{})
83+
require.NoError(t, err)
84+
require.NotNil(t, fs)
85+
86+
p := []string{}
87+
err = fs.Walk(context.Background(), ".", iofs.WalkDirFunc(func(path string, info iofs.DirEntry, err error) error {
88+
p = append(p, path)
89+
return nil
90+
}))
91+
require.NoError(t, err)
92+
require.Equal(t, []string{
93+
"dir",
94+
filepath.Join("dir", "test.txt"),
95+
// TODO(nicks): "unmapped-dir" should be included in the walk. It is not
96+
// because of an upstream bug in fsutil. See:
97+
// https://github.com/tonistiigi/fsutil/pull/203
98+
//
99+
// "unmapped-dir",
100+
filepath.Join("unmapped-dir", "test.txt"),
101+
}, p)
102+
}
103+
104+
func newCacheManager(ctx context.Context, t *testing.T, idmap *idtools.IdentityMapping) (cm cache.Manager, err error) {
105+
ns, ok := namespaces.Namespace(ctx)
106+
if !ok {
107+
return nil, errors.Errorf("namespace required for test")
108+
}
109+
110+
tmpdir := t.TempDir()
111+
112+
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
113+
if err != nil {
114+
return nil, err
115+
}
116+
117+
store, err := local.NewStore(tmpdir)
118+
if err != nil {
119+
return nil, err
120+
}
121+
122+
db, err := bolt.Open(filepath.Join(tmpdir, "containerdmeta.db"), 0644, nil)
123+
if err != nil {
124+
return nil, err
125+
}
126+
t.Cleanup(func() {
127+
require.NoError(t, db.Close())
128+
})
129+
130+
sn := "native-snapshotter"
131+
mdb := ctdmetadata.NewDB(db, store, map[string]snapshots.Snapshotter{
132+
sn: snapshotter,
133+
})
134+
if err := mdb.Init(context.TODO()); err != nil {
135+
return nil, err
136+
}
137+
138+
lm := leaseutil.WithNamespace(ctdmetadata.NewLeaseManager(mdb), ns)
139+
c := mdb.ContentStore()
140+
applier := winlayers.NewFileSystemApplierWithWindows(c, apply.NewFileSystemApplier(c))
141+
differ := winlayers.NewWalkingDiffWithWindows(c, walking.NewWalkingDiff(c))
142+
143+
md, err := metadata.NewStore(filepath.Join(tmpdir, "metadata.db"))
144+
if err != nil {
145+
return nil, err
146+
}
147+
t.Cleanup(func() {
148+
require.NoError(t, md.Close())
149+
})
150+
151+
cm, err = cache.NewManager(cache.ManagerOpt{
152+
Snapshotter: snapshot.FromContainerdSnapshotter(sn, containerdsnapshot.NSSnapshotter(ns, mdb.Snapshotter(sn)), idmap),
153+
MetadataStore: md,
154+
ContentStore: c,
155+
Applier: applier,
156+
Differ: differ,
157+
LeaseManager: lm,
158+
GarbageCollect: mdb.GarbageCollect,
159+
MountPoolRoot: filepath.Join(tmpdir, "cachemounts"),
160+
})
161+
if err != nil {
162+
return nil, err
163+
}
164+
t.Cleanup(func() {
165+
require.NoError(t, cm.Close())
166+
})
167+
168+
return cm, nil
169+
}

0 commit comments

Comments
 (0)