github.com/lalkh/containerd@v1.4.3/snapshots/testsuite/issues.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package testsuite
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/containerd/containerd/snapshots"
    27  	"github.com/containerd/continuity/fs/fstest"
    28  )
    29  
    30  // Checks which cover former issues found in older layering models.
    31  //
    32  // NOTE: In older models, applying with tar was used to create read only layers,
    33  // however with the snapshot model read only layers are created just using
    34  // mounts and commits. Read write layers are a separate type of snapshot which
    35  // is not committed, avoiding any confusion in the snapshotter about whether
    36  // a snapshot will be mutated in the future.
    37  
    38  // checkLayerFileUpdate tests the update of a single file in an upper layer
    39  // Cause of issue was originally related to tar, snapshot should be able to
    40  // avoid such issues by not relying on tar to create layers.
    41  // See https://github.com/docker/docker/issues/21555
    42  func checkLayerFileUpdate(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
    43  	l1Init := fstest.Apply(
    44  		fstest.CreateDir("/etc", 0700),
    45  		fstest.CreateFile("/etc/hosts", []byte("mydomain 10.0.0.1"), 0644),
    46  		fstest.CreateFile("/etc/profile", []byte("PATH=/usr/bin"), 0644),
    47  	)
    48  	l2Init := fstest.Apply(
    49  		fstest.CreateFile("/etc/hosts", []byte("mydomain 10.0.0.2"), 0644),
    50  		fstest.CreateFile("/etc/profile", []byte("PATH=/usr/bin"), 0666),
    51  		fstest.CreateDir("/root", 0700),
    52  		fstest.CreateFile("/root/.bashrc", []byte("PATH=/usr/sbin:/usr/bin"), 0644),
    53  	)
    54  
    55  	var sleepTime time.Duration
    56  
    57  	// run 5 times to account for sporadic failure
    58  	for i := 0; i < 5; i++ {
    59  		time.Sleep(sleepTime)
    60  
    61  		if err := checkSnapshots(ctx, sn, work, l1Init, l2Init); err != nil {
    62  			t.Fatalf("Check snapshots failed: %+v", err)
    63  		}
    64  
    65  		// Sleep until next second boundary before running again
    66  		nextTime := time.Now()
    67  		sleepTime = time.Unix(nextTime.Unix()+1, 0).Sub(nextTime)
    68  	}
    69  }
    70  
    71  // checkRemoveDirectoryInLowerLayer
    72  // See https://github.com/docker/docker/issues/25244
    73  func checkRemoveDirectoryInLowerLayer(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
    74  	l1Init := fstest.Apply(
    75  		fstest.CreateDir("/lib", 0700),
    76  		fstest.CreateFile("/lib/hidden", []byte{}, 0644),
    77  	)
    78  	l2Init := fstest.Apply(
    79  		fstest.RemoveAll("/lib"),
    80  		fstest.CreateDir("/lib", 0700),
    81  		fstest.CreateFile("/lib/not-hidden", []byte{}, 0644),
    82  	)
    83  	l3Init := fstest.Apply(
    84  		fstest.CreateFile("/lib/newfile", []byte{}, 0644),
    85  	)
    86  
    87  	if err := checkSnapshots(ctx, sn, work, l1Init, l2Init, l3Init); err != nil {
    88  		t.Fatalf("Check snapshots failed: %+v", err)
    89  	}
    90  }
    91  
    92  // checkChown
    93  // See https://github.com/docker/docker/issues/20240 aufs
    94  // See https://github.com/docker/docker/issues/24913 overlay
    95  // see https://github.com/docker/docker/issues/28391 overlay2
    96  func checkChown(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
    97  	l1Init := fstest.Apply(
    98  		fstest.CreateDir("/opt", 0700),
    99  		fstest.CreateDir("/opt/a", 0700),
   100  		fstest.CreateDir("/opt/a/b", 0700),
   101  		fstest.CreateFile("/opt/a/b/file.txt", []byte("hello"), 0644),
   102  	)
   103  	l2Init := fstest.Apply(
   104  		fstest.Chown("/opt", 1, 1),
   105  		fstest.Chown("/opt/a", 1, 1),
   106  		fstest.Chown("/opt/a/b", 1, 1),
   107  		fstest.Chown("/opt/a/b/file.txt", 1, 1),
   108  	)
   109  
   110  	if err := checkSnapshots(ctx, sn, work, l1Init, l2Init); err != nil {
   111  		t.Fatalf("Check snapshots failed: %+v", err)
   112  	}
   113  }
   114  
   115  // checkRename
   116  // https://github.com/docker/docker/issues/25409
   117  func checkRename(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
   118  	t.Skip("rename test still fails on some kernels with overlay")
   119  	l1Init := fstest.Apply(
   120  		fstest.CreateDir("/dir1", 0700),
   121  		fstest.CreateDir("/somefiles", 0700),
   122  		fstest.CreateFile("/somefiles/f1", []byte("was here first!"), 0644),
   123  		fstest.CreateFile("/somefiles/f2", []byte("nothing interesting"), 0644),
   124  	)
   125  	l2Init := fstest.Apply(
   126  		fstest.Rename("/dir1", "/dir2"),
   127  		fstest.CreateFile("/somefiles/f1-overwrite", []byte("new content 1"), 0644),
   128  		fstest.Rename("/somefiles/f1-overwrite", "/somefiles/f1"),
   129  		fstest.Rename("/somefiles/f2", "/somefiles/f3"),
   130  	)
   131  
   132  	if err := checkSnapshots(ctx, sn, work, l1Init, l2Init); err != nil {
   133  		t.Fatalf("Check snapshots failed: %+v", err)
   134  	}
   135  }
   136  
   137  // checkDirectoryPermissionOnCommit
   138  // https://github.com/docker/docker/issues/27298
   139  func checkDirectoryPermissionOnCommit(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
   140  	l1Init := fstest.Apply(
   141  		fstest.CreateDir("/dir1", 0700),
   142  		fstest.CreateDir("/dir2", 0700),
   143  		fstest.CreateDir("/dir3", 0700),
   144  		fstest.CreateDir("/dir4", 0700),
   145  		fstest.CreateFile("/dir4/f1", []byte("..."), 0644),
   146  		fstest.CreateDir("/dir5", 0700),
   147  		fstest.CreateFile("/dir5/f1", []byte("..."), 0644),
   148  		fstest.Chown("/dir1", 1, 1),
   149  		fstest.Chown("/dir2", 1, 1),
   150  		fstest.Chown("/dir3", 1, 1),
   151  		fstest.Chown("/dir5", 1, 1),
   152  		fstest.Chown("/dir5/f1", 1, 1),
   153  	)
   154  	l2Init := fstest.Apply(
   155  		fstest.Chown("/dir2", 0, 0),
   156  		fstest.RemoveAll("/dir3"),
   157  		fstest.Chown("/dir4", 1, 1),
   158  		fstest.Chown("/dir4/f1", 1, 1),
   159  	)
   160  	l3Init := fstest.Apply(
   161  		fstest.CreateDir("/dir3", 0700),
   162  		fstest.Chown("/dir3", 1, 1),
   163  		fstest.RemoveAll("/dir5"),
   164  		fstest.CreateDir("/dir5", 0700),
   165  		fstest.Chown("/dir5", 1, 1),
   166  	)
   167  
   168  	if err := checkSnapshots(ctx, sn, work, l1Init, l2Init, l3Init); err != nil {
   169  		t.Fatalf("Check snapshots failed: %+v", err)
   170  	}
   171  }
   172  
   173  // checkStatInWalk ensures that a stat can be called during a walk
   174  func checkStatInWalk(ctx context.Context, t *testing.T, sn snapshots.Snapshotter, work string) {
   175  	prefix := "stats-in-walk-"
   176  	if err := createNamedSnapshots(ctx, sn, prefix); err != nil {
   177  		t.Fatal(err)
   178  	}
   179  
   180  	err := sn.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
   181  		if !strings.HasPrefix(si.Name, prefix) {
   182  			// Only stat snapshots from this test
   183  			return nil
   184  		}
   185  		si2, err := sn.Stat(ctx, si.Name)
   186  		if err != nil {
   187  			return err
   188  		}
   189  
   190  		return checkInfo(si, si2)
   191  	})
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  }
   196  
   197  func createNamedSnapshots(ctx context.Context, snapshotter snapshots.Snapshotter, ns string) error {
   198  	c1 := fmt.Sprintf("%sc1", ns)
   199  	c2 := fmt.Sprintf("%sc2", ns)
   200  	if _, err := snapshotter.Prepare(ctx, c1+"-a", "", opt); err != nil {
   201  		return err
   202  	}
   203  	if err := snapshotter.Commit(ctx, c1, c1+"-a", opt); err != nil {
   204  		return err
   205  	}
   206  	if _, err := snapshotter.Prepare(ctx, c2+"-a", c1, opt); err != nil {
   207  		return err
   208  	}
   209  	if err := snapshotter.Commit(ctx, c2, c2+"-a", opt); err != nil {
   210  		return err
   211  	}
   212  	if _, err := snapshotter.Prepare(ctx, fmt.Sprintf("%sa1", ns), c2, opt); err != nil {
   213  		return err
   214  	}
   215  	if _, err := snapshotter.View(ctx, fmt.Sprintf("%sv1", ns), c2, opt); err != nil {
   216  		return err
   217  	}
   218  	return nil
   219  }
   220  
   221  // More issues to test
   222  //
   223  // checkRemoveAfterCommit
   224  // See https://github.com/docker/docker/issues/24309
   225  //
   226  // checkUnixDomainSockets
   227  // See https://github.com/docker/docker/issues/12080
   228  //
   229  // checkDirectoryInodeStability
   230  // See https://github.com/docker/docker/issues/19647
   231  //
   232  // checkOpenFileInodeStability
   233  // See https://github.com/docker/docker/issues/12327
   234  //
   235  // checkGetCWD
   236  // See https://github.com/docker/docker/issues/19082
   237  //
   238  // checkChmod
   239  // See https://github.com/docker/machine/issues/3327
   240  //
   241  // checkRemoveInWalk
   242  // Allow mutations during walk without deadlocking