github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/rootfs/init.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 rootfs 18 19 import ( 20 "context" 21 "fmt" 22 "io/ioutil" 23 "os" 24 25 "github.com/containerd/containerd/log" 26 "github.com/containerd/containerd/mount" 27 "github.com/containerd/containerd/snapshots" 28 digest "github.com/opencontainers/go-digest" 29 "github.com/pkg/errors" 30 ) 31 32 var ( 33 initializers = map[string]initializerFunc{} 34 ) 35 36 type initializerFunc func(string) error 37 38 // Mounter handles mount and unmount 39 type Mounter interface { 40 Mount(target string, mounts ...mount.Mount) error 41 Unmount(target string) error 42 } 43 44 // InitRootFS initializes the snapshot for use as a rootfs 45 func InitRootFS(ctx context.Context, name string, parent digest.Digest, readonly bool, snapshotter snapshots.Snapshotter, mounter Mounter) ([]mount.Mount, error) { 46 _, err := snapshotter.Stat(ctx, name) 47 if err == nil { 48 return nil, errors.Errorf("rootfs already exists") 49 } 50 // TODO: ensure not exist error once added to snapshot package 51 52 parentS := parent.String() 53 54 initName := defaultInitializer 55 initFn := initializers[initName] 56 if initFn != nil { 57 parentS, err = createInitLayer(ctx, parentS, initName, initFn, snapshotter, mounter) 58 if err != nil { 59 return nil, err 60 } 61 } 62 63 if readonly { 64 return snapshotter.View(ctx, name, parentS) 65 } 66 67 return snapshotter.Prepare(ctx, name, parentS) 68 } 69 70 func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshots.Snapshotter, mounter Mounter) (string, error) { 71 initS := fmt.Sprintf("%s %s", parent, initName) 72 if _, err := snapshotter.Stat(ctx, initS); err == nil { 73 return initS, nil 74 } 75 // TODO: ensure not exist error once added to snapshot package 76 77 // Create tempdir 78 td, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "create-init-") 79 if err != nil { 80 return "", err 81 } 82 defer os.RemoveAll(td) 83 84 mounts, err := snapshotter.Prepare(ctx, td, parent) 85 if err != nil { 86 return "", err 87 } 88 89 defer func() { 90 if err != nil { 91 if rerr := snapshotter.Remove(ctx, td); rerr != nil { 92 log.G(ctx).Errorf("Failed to remove snapshot %s: %v", td, rerr) 93 } 94 } 95 }() 96 97 if err = mounter.Mount(td, mounts...); err != nil { 98 return "", err 99 } 100 101 if err = initFn(td); err != nil { 102 if merr := mounter.Unmount(td); merr != nil { 103 log.G(ctx).Errorf("Failed to unmount %s: %v", td, merr) 104 } 105 return "", err 106 } 107 108 if err = mounter.Unmount(td); err != nil { 109 return "", err 110 } 111 112 if err := snapshotter.Commit(ctx, initS, td); err != nil { 113 return "", err 114 } 115 116 return initS, nil 117 }