github.com/containerd/Containerd@v1.4.13/metadata/snapshot_test.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 metadata 18 19 import ( 20 "context" 21 "os" 22 "path/filepath" 23 "reflect" 24 "runtime" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/containerd/containerd/errdefs" 30 "github.com/containerd/containerd/filters" 31 "github.com/containerd/containerd/mount" 32 "github.com/containerd/containerd/namespaces" 33 "github.com/containerd/containerd/pkg/testutil" 34 "github.com/containerd/containerd/snapshots" 35 "github.com/containerd/containerd/snapshots/native" 36 "github.com/containerd/containerd/snapshots/testsuite" 37 "github.com/pkg/errors" 38 bolt "go.etcd.io/bbolt" 39 ) 40 41 func newTestSnapshotter(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { 42 nativeRoot := filepath.Join(root, "native") 43 if err := os.Mkdir(nativeRoot, 0770); err != nil { 44 return nil, nil, err 45 } 46 snapshotter, err := native.NewSnapshotter(nativeRoot) 47 if err != nil { 48 return nil, nil, err 49 } 50 51 db, err := bolt.Open(filepath.Join(root, "metadata.db"), 0660, nil) 52 if err != nil { 53 return nil, nil, err 54 } 55 56 sn := NewDB(db, nil, map[string]snapshots.Snapshotter{"native": snapshotter}).Snapshotter("native") 57 58 return sn, func() error { 59 if err := sn.Close(); err != nil { 60 return err 61 } 62 return db.Close() 63 }, nil 64 } 65 66 func TestMetadata(t *testing.T) { 67 if runtime.GOOS == "windows" { 68 t.Skip("snapshotter not implemented on windows") 69 } 70 // Snapshot tests require mounting, still requires root 71 testutil.RequiresRoot(t) 72 testsuite.SnapshotterSuite(t, "Metadata", newTestSnapshotter) 73 } 74 75 func TestSnapshotterWithRef(t *testing.T) { 76 ctx, db, done := testDB(t, withSnapshotter("tmp", func(string) (snapshots.Snapshotter, error) { 77 return NewTmpSnapshotter(), nil 78 })) 79 defer done() 80 81 sn := db.Snapshotter("tmp") 82 83 test1opt := snapshots.WithLabels( 84 map[string]string{ 85 labelSnapshotRef: "test1", 86 }, 87 ) 88 89 _, err := sn.Prepare(ctx, "test1-tmp", "", test1opt) 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 err = sn.Commit(ctx, "test1", "test1-tmp", test1opt) 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 ctx2 := namespaces.WithNamespace(ctx, "testing2") 100 101 _, err = sn.Prepare(ctx2, "test1-tmp", "", test1opt) 102 if err == nil { 103 t.Fatal("expected already exists error") 104 } else if !errdefs.IsAlreadyExists(err) { 105 t.Fatal(err) 106 } 107 108 // test1 should now be in the namespace 109 _, err = sn.Stat(ctx2, "test1") 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 test2opt := snapshots.WithLabels( 115 map[string]string{ 116 labelSnapshotRef: "test2", 117 }, 118 ) 119 120 _, err = sn.Prepare(ctx2, "test2-tmp", "test1", test2opt) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 // In original namespace, but not committed 126 _, err = sn.Prepare(ctx, "test2-tmp", "test1", test2opt) 127 if err != nil { 128 t.Fatal(err) 129 } 130 131 err = sn.Commit(ctx2, "test2", "test2-tmp", test2opt) 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 // See note in Commit function for why 137 // this does not return ErrAlreadyExists 138 err = sn.Commit(ctx, "test2", "test2-tmp", test2opt) 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 // This should error out, already exists in namespace 144 // despite mismatched parent 145 _, err = sn.Prepare(ctx2, "test2-tmp-again", "", test2opt) 146 if err == nil { 147 t.Fatal("expected already exists error") 148 } else if !errdefs.IsAlreadyExists(err) { 149 t.Fatal(err) 150 } 151 152 // In original namespace, but already exists 153 _, err = sn.Prepare(ctx, "test2-tmp-again", "test1", test2opt) 154 if err == nil { 155 t.Fatal("expected already exists error") 156 } else if !errdefs.IsAlreadyExists(err) { 157 t.Fatal(err) 158 } 159 160 // Now try a third namespace 161 162 ctx3 := namespaces.WithNamespace(ctx, "testing3") 163 164 // This should error out, matching parent not found 165 _, err = sn.Prepare(ctx3, "test2-tmp", "", test2opt) 166 if err != nil { 167 t.Fatal(err) 168 } 169 170 // Remove, not going to use yet 171 err = sn.Remove(ctx3, "test2-tmp") 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 _, err = sn.Prepare(ctx3, "test2-tmp", "test1", test2opt) 177 if err == nil { 178 t.Fatal("expected not error") 179 } else if !errdefs.IsNotFound(err) { 180 t.Fatal(err) 181 } 182 183 _, err = sn.Prepare(ctx3, "test1-tmp", "", test1opt) 184 if err == nil { 185 t.Fatal("expected already exists error") 186 } else if !errdefs.IsAlreadyExists(err) { 187 t.Fatal(err) 188 } 189 190 _, err = sn.Prepare(ctx3, "test2-tmp", "test1", test2opt) 191 if err == nil { 192 t.Fatal("expected already exists error") 193 } else if !errdefs.IsAlreadyExists(err) { 194 t.Fatal(err) 195 } 196 } 197 198 func TestFilterInheritedLabels(t *testing.T) { 199 tests := []struct { 200 labels map[string]string 201 expected map[string]string 202 }{ 203 { 204 nil, 205 nil, 206 }, 207 { 208 map[string]string{}, 209 map[string]string{}, 210 }, 211 { 212 map[string]string{"": ""}, 213 map[string]string{}, 214 }, 215 { 216 map[string]string{"foo": "bar"}, 217 map[string]string{}, 218 }, 219 { 220 map[string]string{inheritedLabelsPrefix + "foo": "bar"}, 221 map[string]string{inheritedLabelsPrefix + "foo": "bar"}, 222 }, 223 { 224 map[string]string{inheritedLabelsPrefix + "foo": "bar", "qux": "qaz"}, 225 map[string]string{inheritedLabelsPrefix + "foo": "bar"}, 226 }, 227 } 228 229 for _, test := range tests { 230 if actual := snapshots.FilterInheritedLabels(test.labels); !reflect.DeepEqual(actual, test.expected) { 231 t.Fatalf("expected %v but got %v", test.expected, actual) 232 } 233 } 234 } 235 236 type tmpSnapshotter struct { 237 l sync.Mutex 238 snapshots map[string]snapshots.Info 239 targets map[string][]string 240 } 241 242 func NewTmpSnapshotter() snapshots.Snapshotter { 243 return &tmpSnapshotter{ 244 snapshots: map[string]snapshots.Info{}, 245 targets: map[string][]string{}, 246 } 247 } 248 249 func (s *tmpSnapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { 250 s.l.Lock() 251 defer s.l.Unlock() 252 i, ok := s.snapshots[key] 253 if !ok { 254 return snapshots.Info{}, errdefs.ErrNotFound 255 } 256 return i, nil 257 } 258 259 func (s *tmpSnapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { 260 s.l.Lock() 261 defer s.l.Unlock() 262 263 i, ok := s.snapshots[info.Name] 264 if !ok { 265 return snapshots.Info{}, errdefs.ErrNotFound 266 } 267 268 for k, v := range info.Labels { 269 i.Labels[k] = v 270 } 271 272 s.snapshots[i.Name] = i 273 274 return i, nil 275 } 276 277 func (s *tmpSnapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { 278 s.l.Lock() 279 defer s.l.Unlock() 280 _, ok := s.snapshots[key] 281 if !ok { 282 return snapshots.Usage{}, errdefs.ErrNotFound 283 } 284 return snapshots.Usage{}, nil 285 } 286 287 func (s *tmpSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { 288 s.l.Lock() 289 defer s.l.Unlock() 290 _, ok := s.snapshots[key] 291 if !ok { 292 return nil, errdefs.ErrNotFound 293 } 294 return []mount.Mount{}, nil 295 } 296 297 func (s *tmpSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { 298 return s.create(ctx, key, parent, snapshots.KindActive, opts...) 299 } 300 301 func (s *tmpSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { 302 return s.create(ctx, key, parent, snapshots.KindView, opts...) 303 } 304 305 func (s *tmpSnapshotter) create(ctx context.Context, key, parent string, kind snapshots.Kind, opts ...snapshots.Opt) ([]mount.Mount, error) { 306 s.l.Lock() 307 defer s.l.Unlock() 308 309 var base snapshots.Info 310 for _, opt := range opts { 311 if err := opt(&base); err != nil { 312 return nil, err 313 } 314 } 315 base.Name = key 316 base.Kind = kind 317 318 target := base.Labels[labelSnapshotRef] 319 if target != "" { 320 for _, name := range s.targets[target] { 321 if s.snapshots[name].Parent == parent { 322 return nil, errors.Wrap(errdefs.ErrAlreadyExists, "found target") 323 } 324 } 325 } 326 327 if parent != "" { 328 _, ok := s.snapshots[parent] 329 if !ok { 330 return nil, errdefs.ErrNotFound 331 } 332 base.Parent = parent 333 } 334 335 ts := time.Now().UTC() 336 base.Created = ts 337 base.Updated = ts 338 339 s.snapshots[base.Name] = base 340 341 return []mount.Mount{}, nil 342 } 343 344 func (s *tmpSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { 345 s.l.Lock() 346 defer s.l.Unlock() 347 348 var base snapshots.Info 349 for _, opt := range opts { 350 if err := opt(&base); err != nil { 351 return err 352 } 353 } 354 base.Name = name 355 base.Kind = snapshots.KindCommitted 356 357 if _, ok := s.snapshots[name]; ok { 358 return errors.Wrap(errdefs.ErrAlreadyExists, "found name") 359 } 360 361 src, ok := s.snapshots[key] 362 if !ok { 363 return errdefs.ErrNotFound 364 } 365 if src.Kind == snapshots.KindCommitted { 366 return errdefs.ErrInvalidArgument 367 } 368 base.Parent = src.Parent 369 370 ts := time.Now().UTC() 371 base.Created = ts 372 base.Updated = ts 373 374 s.snapshots[name] = base 375 delete(s.snapshots, key) 376 377 if target := base.Labels[labelSnapshotRef]; target != "" { 378 s.targets[target] = append(s.targets[target], name) 379 } 380 381 return nil 382 } 383 384 func (s *tmpSnapshotter) Remove(ctx context.Context, key string) error { 385 s.l.Lock() 386 defer s.l.Unlock() 387 388 sn, ok := s.snapshots[key] 389 if !ok { 390 return errdefs.ErrNotFound 391 } 392 delete(s.snapshots, key) 393 394 // scan and remove all instances of name as a target 395 for ref, names := range s.targets { 396 for i := range names { 397 if names[i] == sn.Name { 398 if len(names) == 1 { 399 delete(s.targets, ref) 400 } else { 401 copy(names[i:], names[i+1:]) 402 s.targets[ref] = names[:len(names)-1] 403 } 404 break 405 } 406 } 407 } 408 409 return nil 410 } 411 412 func (s *tmpSnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { 413 s.l.Lock() 414 defer s.l.Unlock() 415 416 filter, err := filters.ParseAll(fs...) 417 if err != nil { 418 return err 419 } 420 421 // call func for each 422 for _, i := range s.snapshots { 423 if filter.Match(adaptSnapshot(i)) { 424 if err := fn(ctx, i); err != nil { 425 return err 426 } 427 } 428 } 429 return nil 430 } 431 432 func (s *tmpSnapshotter) Close() error { 433 return nil 434 }