github.com/containerd/Containerd@v1.4.13/snapshots/testsuite/helpers.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  	"io/ioutil"
    23  	"math/rand"
    24  	"os"
    25  
    26  	"github.com/containerd/containerd/mount"
    27  	"github.com/containerd/containerd/snapshots"
    28  	"github.com/containerd/continuity/fs/fstest"
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  func applyToMounts(m []mount.Mount, work string, a fstest.Applier) (err error) {
    33  	td, err := ioutil.TempDir(work, "prepare")
    34  	if err != nil {
    35  		return errors.Wrap(err, "failed to create temp dir")
    36  	}
    37  	defer os.RemoveAll(td)
    38  
    39  	if err := mount.All(m, td); err != nil {
    40  		return errors.Wrap(err, "failed to mount")
    41  	}
    42  	defer func() {
    43  		if err1 := mount.UnmountAll(td, umountflags); err == nil {
    44  			err = errors.Wrap(err1, "failed to unmount")
    45  		}
    46  	}()
    47  
    48  	return a.Apply(td)
    49  }
    50  
    51  // createSnapshot creates a new snapshot in the snapshotter
    52  // given an applier to run on top of the given parent.
    53  func createSnapshot(ctx context.Context, sn snapshots.Snapshotter, parent, work string, a fstest.Applier) (string, error) {
    54  	n := fmt.Sprintf("%p-%d", a, rand.Int())
    55  	prepare := fmt.Sprintf("%s-prepare", n)
    56  
    57  	m, err := sn.Prepare(ctx, prepare, parent, opt)
    58  	if err != nil {
    59  		return "", errors.Wrap(err, "failed to prepare snapshot")
    60  	}
    61  
    62  	if err := applyToMounts(m, work, a); err != nil {
    63  		return "", errors.Wrap(err, "failed to apply")
    64  	}
    65  
    66  	if err := sn.Commit(ctx, n, prepare, opt); err != nil {
    67  		return "", errors.Wrap(err, "failed to commit")
    68  	}
    69  
    70  	return n, nil
    71  }
    72  
    73  func checkSnapshot(ctx context.Context, sn snapshots.Snapshotter, work, name, check string) (err error) {
    74  	td, err := ioutil.TempDir(work, "check")
    75  	if err != nil {
    76  		return errors.Wrap(err, "failed to create temp dir")
    77  	}
    78  	defer func() {
    79  		if err1 := os.RemoveAll(td); err == nil {
    80  			err = errors.Wrapf(err1, "failed to remove temporary directory %s", td)
    81  		}
    82  	}()
    83  
    84  	view := fmt.Sprintf("%s-view", name)
    85  	m, err := sn.View(ctx, view, name, opt)
    86  	if err != nil {
    87  		return errors.Wrap(err, "failed to create view")
    88  	}
    89  	defer func() {
    90  		if err1 := sn.Remove(ctx, view); err == nil {
    91  			err = errors.Wrap(err1, "failed to remove view")
    92  		}
    93  	}()
    94  
    95  	if err := mount.All(m, td); err != nil {
    96  		return errors.Wrap(err, "failed to mount")
    97  	}
    98  	defer func() {
    99  		if err1 := mount.UnmountAll(td, umountflags); err == nil {
   100  			err = errors.Wrap(err1, "failed to unmount view")
   101  		}
   102  	}()
   103  
   104  	if err := fstest.CheckDirectoryEqual(check, td); err != nil {
   105  		return errors.Wrap(err, "check directory failed")
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // checkSnapshots creates a new chain of snapshots in the given snapshotter
   112  // using the provided appliers, checking each snapshot created in a view
   113  // against the changes applied to a single directory.
   114  func checkSnapshots(ctx context.Context, sn snapshots.Snapshotter, work string, as ...fstest.Applier) error {
   115  	td, err := ioutil.TempDir(work, "flat")
   116  	if err != nil {
   117  		return errors.Wrap(err, "failed to create temp dir")
   118  	}
   119  	defer os.RemoveAll(td)
   120  
   121  	var parentID string
   122  	for i, a := range as {
   123  		s, err := createSnapshot(ctx, sn, parentID, work, a)
   124  		if err != nil {
   125  			return errors.Wrapf(err, "failed to create snapshot %d", i+1)
   126  		}
   127  
   128  		if err := a.Apply(td); err != nil {
   129  			return errors.Wrapf(err, "failed to apply to check directory on %d", i+1)
   130  		}
   131  
   132  		if err := checkSnapshot(ctx, sn, work, s, td); err != nil {
   133  			return errors.Wrapf(err, "snapshot check failed on snapshot %d", i+1)
   134  		}
   135  
   136  		parentID = s
   137  	}
   138  	return nil
   139  
   140  }
   141  
   142  // checkInfo checks that the infos are the same
   143  func checkInfo(si1, si2 snapshots.Info) error {
   144  	if si1.Kind != si2.Kind {
   145  		return errors.Errorf("Expected kind %v, got %v", si1.Kind, si2.Kind)
   146  	}
   147  	if si1.Name != si2.Name {
   148  		return errors.Errorf("Expected name %v, got %v", si1.Name, si2.Name)
   149  	}
   150  	if si1.Parent != si2.Parent {
   151  		return errors.Errorf("Expected Parent %v, got %v", si1.Parent, si2.Parent)
   152  	}
   153  	if len(si1.Labels) != len(si2.Labels) {
   154  		return errors.Errorf("Expected %d labels, got %d", len(si1.Labels), len(si2.Labels))
   155  	}
   156  	for k, l1 := range si1.Labels {
   157  		l2 := si2.Labels[k]
   158  		if l1 != l2 {
   159  			return errors.Errorf("Expected label %v, got %v", l1, l2)
   160  		}
   161  	}
   162  	if si1.Created != si2.Created {
   163  		return errors.Errorf("Expected Created %v, got %v", si1.Created, si2.Created)
   164  	}
   165  	if si1.Updated != si2.Updated {
   166  		return errors.Errorf("Expected Updated %v, got %v", si1.Updated, si2.Updated)
   167  	}
   168  
   169  	return nil
   170  }