github.com/demonoid81/containerd@v1.3.4/snapshots/overlay/overlay_test.go (about)

     1  // +build linux
     2  
     3  /*
     4     Copyright The containerd Authors.
     5  
     6     Licensed under the Apache License, Version 2.0 (the "License");
     7     you may not use this file except in compliance with the License.
     8     You may obtain a copy of the License at
     9  
    10         http://www.apache.org/licenses/LICENSE-2.0
    11  
    12     Unless required by applicable law or agreed to in writing, software
    13     distributed under the License is distributed on an "AS IS" BASIS,
    14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15     See the License for the specific language governing permissions and
    16     limitations under the License.
    17  */
    18  
    19  package overlay
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"syscall"
    28  	"testing"
    29  
    30  	"github.com/containerd/containerd/mount"
    31  	"github.com/containerd/containerd/pkg/testutil"
    32  	"github.com/containerd/containerd/snapshots"
    33  	"github.com/containerd/containerd/snapshots/storage"
    34  	"github.com/containerd/containerd/snapshots/testsuite"
    35  )
    36  
    37  func newSnapshotter(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) {
    38  	snapshotter, err := NewSnapshotter(root)
    39  	if err != nil {
    40  		return nil, nil, err
    41  	}
    42  
    43  	return snapshotter, func() error { return snapshotter.Close() }, nil
    44  }
    45  
    46  func TestOverlay(t *testing.T) {
    47  	testutil.RequiresRoot(t)
    48  	testsuite.SnapshotterSuite(t, "Overlay", newSnapshotter)
    49  }
    50  
    51  func TestOverlayMounts(t *testing.T) {
    52  	ctx := context.TODO()
    53  	root, err := ioutil.TempDir("", "overlay")
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	defer os.RemoveAll(root)
    58  	o, _, err := newSnapshotter(ctx, root)
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	mounts, err := o.Prepare(ctx, "/tmp/test", "")
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	if len(mounts) != 1 {
    67  		t.Errorf("should only have 1 mount but received %d", len(mounts))
    68  	}
    69  	m := mounts[0]
    70  	if m.Type != "bind" {
    71  		t.Errorf("mount type should be bind but received %q", m.Type)
    72  	}
    73  	expected := filepath.Join(root, "snapshots", "1", "fs")
    74  	if m.Source != expected {
    75  		t.Errorf("expected source %q but received %q", expected, m.Source)
    76  	}
    77  	if m.Options[0] != "rw" {
    78  		t.Errorf("expected mount option rw but received %q", m.Options[0])
    79  	}
    80  	if m.Options[1] != "rbind" {
    81  		t.Errorf("expected mount option rbind but received %q", m.Options[1])
    82  	}
    83  }
    84  
    85  func TestOverlayCommit(t *testing.T) {
    86  	ctx := context.TODO()
    87  	root, err := ioutil.TempDir("", "overlay")
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	defer os.RemoveAll(root)
    92  	o, _, err := newSnapshotter(ctx, root)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	key := "/tmp/test"
    97  	mounts, err := o.Prepare(ctx, key, "")
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  	m := mounts[0]
   102  	if err := ioutil.WriteFile(filepath.Join(m.Source, "foo"), []byte("hi"), 0660); err != nil {
   103  		t.Fatal(err)
   104  	}
   105  	if err := o.Commit(ctx, "base", key); err != nil {
   106  		t.Fatal(err)
   107  	}
   108  }
   109  
   110  func TestOverlayOverlayMount(t *testing.T) {
   111  	ctx := context.TODO()
   112  	root, err := ioutil.TempDir("", "overlay")
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	defer os.RemoveAll(root)
   117  	o, _, err := newSnapshotter(ctx, root)
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	key := "/tmp/test"
   122  	if _, err = o.Prepare(ctx, key, ""); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	if err := o.Commit(ctx, "base", key); err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	var mounts []mount.Mount
   129  	if mounts, err = o.Prepare(ctx, "/tmp/layer2", "base"); err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	if len(mounts) != 1 {
   133  		t.Errorf("should only have 1 mount but received %d", len(mounts))
   134  	}
   135  	m := mounts[0]
   136  	if m.Type != "overlay" {
   137  		t.Errorf("mount type should be overlay but received %q", m.Type)
   138  	}
   139  	if m.Source != "overlay" {
   140  		t.Errorf("expected source %q but received %q", "overlay", m.Source)
   141  	}
   142  	var (
   143  		bp    = getBasePath(ctx, o, root, "/tmp/layer2")
   144  		work  = "workdir=" + filepath.Join(bp, "work")
   145  		upper = "upperdir=" + filepath.Join(bp, "fs")
   146  		lower = "lowerdir=" + getParents(ctx, o, root, "/tmp/layer2")[0]
   147  	)
   148  	for i, v := range []string{
   149  		work,
   150  		upper,
   151  		lower,
   152  	} {
   153  		if m.Options[i] != v {
   154  			t.Errorf("expected %q but received %q", v, m.Options[i])
   155  		}
   156  	}
   157  }
   158  
   159  func getBasePath(ctx context.Context, sn snapshots.Snapshotter, root, key string) string {
   160  	o := sn.(*snapshotter)
   161  	ctx, t, err := o.ms.TransactionContext(ctx, false)
   162  	if err != nil {
   163  		panic(err)
   164  	}
   165  	defer t.Rollback()
   166  
   167  	s, err := storage.GetSnapshot(ctx, key)
   168  	if err != nil {
   169  		panic(err)
   170  	}
   171  
   172  	return filepath.Join(root, "snapshots", s.ID)
   173  }
   174  
   175  func getParents(ctx context.Context, sn snapshots.Snapshotter, root, key string) []string {
   176  	o := sn.(*snapshotter)
   177  	ctx, t, err := o.ms.TransactionContext(ctx, false)
   178  	if err != nil {
   179  		panic(err)
   180  	}
   181  	defer t.Rollback()
   182  	s, err := storage.GetSnapshot(ctx, key)
   183  	if err != nil {
   184  		panic(err)
   185  	}
   186  	parents := make([]string, len(s.ParentIDs))
   187  	for i := range s.ParentIDs {
   188  		parents[i] = filepath.Join(root, "snapshots", s.ParentIDs[i], "fs")
   189  	}
   190  	return parents
   191  }
   192  
   193  func TestOverlayOverlayRead(t *testing.T) {
   194  	testutil.RequiresRoot(t)
   195  	ctx := context.TODO()
   196  	root, err := ioutil.TempDir("", "overlay")
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  	defer os.RemoveAll(root)
   201  	o, _, err := newSnapshotter(ctx, root)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	key := "/tmp/test"
   206  	mounts, err := o.Prepare(ctx, key, "")
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	m := mounts[0]
   211  	if err := ioutil.WriteFile(filepath.Join(m.Source, "foo"), []byte("hi"), 0660); err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	if err := o.Commit(ctx, "base", key); err != nil {
   215  		t.Fatal(err)
   216  	}
   217  	if mounts, err = o.Prepare(ctx, "/tmp/layer2", "base"); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	dest := filepath.Join(root, "dest")
   221  	if err := os.Mkdir(dest, 0700); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	if err := mount.All(mounts, dest); err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	defer syscall.Unmount(dest, 0)
   228  	data, err := ioutil.ReadFile(filepath.Join(dest, "foo"))
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	if e := string(data); e != "hi" {
   233  		t.Fatalf("expected file contents hi but got %q", e)
   234  	}
   235  }
   236  
   237  func TestOverlayView(t *testing.T) {
   238  	ctx := context.TODO()
   239  	root, err := ioutil.TempDir("", "overlay")
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	defer os.RemoveAll(root)
   244  	o, _, err := newSnapshotter(ctx, root)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  	key := "/tmp/base"
   249  	mounts, err := o.Prepare(ctx, key, "")
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	m := mounts[0]
   254  	if err := ioutil.WriteFile(filepath.Join(m.Source, "foo"), []byte("hi"), 0660); err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	if err := o.Commit(ctx, "base", key); err != nil {
   258  		t.Fatal(err)
   259  	}
   260  
   261  	key = "/tmp/top"
   262  	_, err = o.Prepare(ctx, key, "base")
   263  	if err != nil {
   264  		t.Fatal(err)
   265  	}
   266  	if err := ioutil.WriteFile(filepath.Join(getParents(ctx, o, root, "/tmp/top")[0], "foo"), []byte("hi, again"), 0660); err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	if err := o.Commit(ctx, "top", key); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  
   273  	mounts, err = o.View(ctx, "/tmp/view1", "base")
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  	if len(mounts) != 1 {
   278  		t.Fatalf("should only have 1 mount but received %d", len(mounts))
   279  	}
   280  	m = mounts[0]
   281  	if m.Type != "bind" {
   282  		t.Errorf("mount type should be bind but received %q", m.Type)
   283  	}
   284  	expected := getParents(ctx, o, root, "/tmp/view1")[0]
   285  	if m.Source != expected {
   286  		t.Errorf("expected source %q but received %q", expected, m.Source)
   287  	}
   288  	if m.Options[0] != "ro" {
   289  		t.Errorf("expected mount option ro but received %q", m.Options[0])
   290  	}
   291  	if m.Options[1] != "rbind" {
   292  		t.Errorf("expected mount option rbind but received %q", m.Options[1])
   293  	}
   294  
   295  	mounts, err = o.View(ctx, "/tmp/view2", "top")
   296  	if err != nil {
   297  		t.Fatal(err)
   298  	}
   299  	if len(mounts) != 1 {
   300  		t.Fatalf("should only have 1 mount but received %d", len(mounts))
   301  	}
   302  	m = mounts[0]
   303  	if m.Type != "overlay" {
   304  		t.Errorf("mount type should be overlay but received %q", m.Type)
   305  	}
   306  	if m.Source != "overlay" {
   307  		t.Errorf("mount source should be overlay but received %q", m.Source)
   308  	}
   309  	if len(m.Options) != 1 {
   310  		t.Errorf("expected 1 mount option but got %d", len(m.Options))
   311  	}
   312  	lowers := getParents(ctx, o, root, "/tmp/view2")
   313  	expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1])
   314  	if m.Options[0] != expected {
   315  		t.Errorf("expected option %q but received %q", expected, m.Options[0])
   316  	}
   317  }