github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/oci/spec_opts_linux.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 oci 20 21 import ( 22 "context" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 "github.com/containerd/containerd/containers" 28 specs "github.com/opencontainers/runtime-spec/specs-go" 29 "golang.org/x/sys/unix" 30 ) 31 32 // WithHostDevices adds all the hosts device nodes to the container's spec 33 func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { 34 setLinux(s) 35 36 devs, err := getDevices("/dev") 37 if err != nil { 38 return err 39 } 40 s.Linux.Devices = append(s.Linux.Devices, devs...) 41 return nil 42 } 43 44 func getDevices(path string) ([]specs.LinuxDevice, error) { 45 files, err := ioutil.ReadDir(path) 46 if err != nil { 47 return nil, err 48 } 49 var out []specs.LinuxDevice 50 for _, f := range files { 51 switch { 52 case f.IsDir(): 53 switch f.Name() { 54 // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 55 // ".udev" added to address https://github.com/opencontainers/runc/issues/2093 56 case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": 57 continue 58 default: 59 sub, err := getDevices(filepath.Join(path, f.Name())) 60 if err != nil { 61 return nil, err 62 } 63 64 out = append(out, sub...) 65 continue 66 } 67 case f.Name() == "console": 68 continue 69 } 70 device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm") 71 if err != nil { 72 if err == ErrNotADevice { 73 continue 74 } 75 if os.IsNotExist(err) { 76 continue 77 } 78 return nil, err 79 } 80 out = append(out, *device) 81 } 82 return out, nil 83 } 84 85 func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { 86 var stat unix.Stat_t 87 if err := unix.Lstat(path, &stat); err != nil { 88 return nil, err 89 } 90 91 var ( 92 // The type is 32bit on mips. 93 devNumber = uint64(stat.Rdev) // nolint: unconvert 94 major = unix.Major(devNumber) 95 minor = unix.Minor(devNumber) 96 ) 97 if major == 0 { 98 return nil, ErrNotADevice 99 } 100 101 var ( 102 devType string 103 mode = stat.Mode 104 ) 105 switch { 106 case mode&unix.S_IFBLK == unix.S_IFBLK: 107 devType = "b" 108 case mode&unix.S_IFCHR == unix.S_IFCHR: 109 devType = "c" 110 } 111 fm := os.FileMode(mode) 112 return &specs.LinuxDevice{ 113 Type: devType, 114 Path: path, 115 Major: int64(major), 116 Minor: int64(minor), 117 FileMode: &fm, 118 UID: &stat.Uid, 119 GID: &stat.Gid, 120 }, nil 121 } 122 123 // WithMemorySwap sets the container's swap in bytes 124 func WithMemorySwap(swap int64) SpecOpts { 125 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 126 setResources(s) 127 if s.Linux.Resources.Memory == nil { 128 s.Linux.Resources.Memory = &specs.LinuxMemory{} 129 } 130 s.Linux.Resources.Memory.Swap = &swap 131 return nil 132 } 133 } 134 135 // WithPidsLimit sets the container's pid limit or maximum 136 func WithPidsLimit(limit int64) SpecOpts { 137 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 138 setResources(s) 139 if s.Linux.Resources.Pids == nil { 140 s.Linux.Resources.Pids = &specs.LinuxPids{} 141 } 142 s.Linux.Resources.Pids.Limit = limit 143 return nil 144 } 145 } 146 147 // WithCPUShares sets the container's cpu shares 148 func WithCPUShares(shares uint64) SpecOpts { 149 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 150 setCPU(s) 151 s.Linux.Resources.CPU.Shares = &shares 152 return nil 153 } 154 } 155 156 // WithCPUs sets the container's cpus/cores for use by the container 157 func WithCPUs(cpus string) SpecOpts { 158 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 159 setCPU(s) 160 s.Linux.Resources.CPU.Cpus = cpus 161 return nil 162 } 163 } 164 165 // WithCPUsMems sets the container's cpu mems for use by the container 166 func WithCPUsMems(mems string) SpecOpts { 167 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 168 setCPU(s) 169 s.Linux.Resources.CPU.Mems = mems 170 return nil 171 } 172 } 173 174 // WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period 175 func WithCPUCFS(quota int64, period uint64) SpecOpts { 176 return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { 177 setCPU(s) 178 s.Linux.Resources.CPU.Quota = "a 179 s.Linux.Resources.CPU.Period = &period 180 return nil 181 } 182 }