github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/runtime/v1/linux/bundle.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package linux 20 21 import ( 22 "context" 23 "crypto/sha256" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 29 "github.com/containerd/containerd/events/exchange" 30 "github.com/containerd/containerd/runtime/linux/runctypes" 31 "github.com/containerd/containerd/runtime/v1/shim" 32 "github.com/containerd/containerd/runtime/v1/shim/client" 33 "github.com/pkg/errors" 34 ) 35 36 // loadBundle loads an existing bundle from disk 37 func loadBundle(id, path, workdir string) *bundle { 38 return &bundle{ 39 id: id, 40 path: path, 41 workDir: workdir, 42 } 43 } 44 45 // newBundle creates a new bundle on disk at the provided path for the given id 46 func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) { 47 if err := os.MkdirAll(path, 0711); err != nil { 48 return nil, err 49 } 50 path = filepath.Join(path, id) 51 if err := os.Mkdir(path, 0711); err != nil { 52 return nil, err 53 } 54 defer func() { 55 if err != nil { 56 os.RemoveAll(path) 57 } 58 }() 59 workDir = filepath.Join(workDir, id) 60 if err := os.MkdirAll(workDir, 0711); err != nil { 61 return nil, err 62 } 63 defer func() { 64 if err != nil { 65 os.RemoveAll(workDir) 66 } 67 }() 68 rootfs := filepath.Join(path, "rootfs") 69 if err := os.MkdirAll(rootfs, 0711); err != nil { 70 return nil, err 71 } 72 err = ioutil.WriteFile(filepath.Join(path, configFilename), spec, 0666) 73 return &bundle{ 74 id: id, 75 path: path, 76 workDir: workDir, 77 }, err 78 } 79 80 type bundle struct { 81 id string 82 path string 83 workDir string 84 } 85 86 // ShimOpt specifies shim options for initialization and connection 87 type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.Opt) 88 89 // ShimRemote is a ShimOpt for connecting and starting a remote shim 90 func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt { 91 return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { 92 config := b.shimConfig(ns, c, ropts) 93 return config, 94 client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler) 95 } 96 } 97 98 // ShimLocal is a ShimOpt for using an in process shim implementation 99 func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt { 100 return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { 101 return b.shimConfig(ns, c, ropts), client.WithLocal(exchange) 102 } 103 } 104 105 // ShimConnect is a ShimOpt for connecting to an existing remote shim 106 func ShimConnect(c *Config, onClose func()) ShimOpt { 107 return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { 108 return b.shimConfig(ns, c, ropts), client.WithConnect(b.decideShimAddress(ns), onClose) 109 } 110 } 111 112 // NewShimClient connects to the shim managing the bundle and tasks creating it if needed 113 func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts ShimOpt, runcOpts *runctypes.RuncOptions) (*client.Client, error) { 114 cfg, opt := getClientOpts(b, namespace, runcOpts) 115 return client.New(ctx, cfg, opt) 116 } 117 118 // Delete deletes the bundle from disk 119 func (b *bundle) Delete() error { 120 err := atomicDelete(b.path) 121 if err == nil { 122 return atomicDelete(b.workDir) 123 } 124 // error removing the bundle path; still attempt removing work dir 125 err2 := atomicDelete(b.workDir) 126 if err2 == nil { 127 return err 128 } 129 return errors.Wrapf(err, "Failed to remove both bundle and workdir locations: %v", err2) 130 } 131 132 func (b *bundle) legacyShimAddress(namespace string) string { 133 return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock") 134 } 135 136 func (b *bundle) shimAddress(namespace string) string { 137 d := sha256.Sum256([]byte(filepath.Join(namespace, b.id))) 138 return filepath.Join(string(filepath.Separator), "containerd-shim", fmt.Sprintf("%x.sock", d)) 139 } 140 141 func (b *bundle) loadAddress() (string, error) { 142 addressPath := filepath.Join(b.path, "address") 143 data, err := ioutil.ReadFile(addressPath) 144 if err != nil { 145 return "", err 146 } 147 return string(data), nil 148 } 149 150 func (b *bundle) decideShimAddress(namespace string) string { 151 address, err := b.loadAddress() 152 if err != nil { 153 return b.legacyShimAddress(namespace) 154 } 155 return address 156 } 157 158 func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config { 159 var ( 160 criuPath string 161 runtimeRoot = c.RuntimeRoot 162 systemdCgroup bool 163 ) 164 if runcOptions != nil { 165 criuPath = runcOptions.CriuPath 166 systemdCgroup = runcOptions.SystemdCgroup 167 if runcOptions.RuntimeRoot != "" { 168 runtimeRoot = runcOptions.RuntimeRoot 169 } 170 } 171 return shim.Config{ 172 Path: b.path, 173 WorkDir: b.workDir, 174 Namespace: namespace, 175 Criu: criuPath, 176 RuntimeRoot: runtimeRoot, 177 SystemdCgroup: systemdCgroup, 178 } 179 } 180 181 // atomicDelete renames the path to a hidden file before removal 182 func atomicDelete(path string) error { 183 // create a hidden dir for an atomic removal 184 atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) 185 if err := os.Rename(path, atomicPath); err != nil { 186 if os.IsNotExist(err) { 187 return nil 188 } 189 return err 190 } 191 return os.RemoveAll(atomicPath) 192 }