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 }