github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/daemon/execdriver/driver_unix.go (about) 1 // +build !windows 2 3 package execdriver 4 5 import ( 6 "encoding/json" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/docker/docker/daemon/execdriver/native/template" 15 "github.com/docker/docker/pkg/idtools" 16 "github.com/docker/docker/pkg/mount" 17 "github.com/docker/go-units" 18 "github.com/opencontainers/runc/libcontainer" 19 "github.com/opencontainers/runc/libcontainer/cgroups/fs" 20 "github.com/opencontainers/runc/libcontainer/configs" 21 blkiodev "github.com/opencontainers/runc/libcontainer/configs" 22 ) 23 24 // Mount contains information for a mount operation. 25 type Mount struct { 26 Source string `json:"source"` 27 Destination string `json:"destination"` 28 Writable bool `json:"writable"` 29 Data string `json:"data"` 30 Propagation string `json:"mountpropagation"` 31 } 32 33 // Resources contains all resource configs for a driver. 34 // Currently these are all for cgroup configs. 35 type Resources struct { 36 CommonResources 37 38 // Fields below here are platform specific 39 40 BlkioWeightDevice []*blkiodev.WeightDevice `json:"blkio_weight_device"` 41 BlkioThrottleReadBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"` 42 BlkioThrottleWriteBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"` 43 BlkioThrottleReadIOpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_iops_device"` 44 BlkioThrottleWriteIOpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_iops_device"` 45 MemorySwap int64 `json:"memory_swap"` 46 KernelMemory int64 `json:"kernel_memory"` 47 CPUQuota int64 `json:"cpu_quota"` 48 CpusetCpus string `json:"cpuset_cpus"` 49 CpusetMems string `json:"cpuset_mems"` 50 CPUPeriod int64 `json:"cpu_period"` 51 Rlimits []*units.Rlimit `json:"rlimits"` 52 OomKillDisable bool `json:"oom_kill_disable"` 53 MemorySwappiness int64 `json:"memory_swappiness"` 54 } 55 56 // ProcessConfig is the platform specific structure that describes a process 57 // that will be run inside a container. 58 type ProcessConfig struct { 59 CommonProcessConfig 60 61 // Fields below here are platform specific 62 Privileged bool `json:"privileged"` 63 User string `json:"user"` 64 Console string `json:"-"` // dev/console path 65 } 66 67 // Ipc settings of the container 68 // It is for IPC namespace setting. Usually different containers 69 // have their own IPC namespace, however this specifies to use 70 // an existing IPC namespace. 71 // You can join the host's or a container's IPC namespace. 72 type Ipc struct { 73 ContainerID string `json:"container_id"` // id of the container to join ipc. 74 HostIpc bool `json:"host_ipc"` 75 } 76 77 // Pid settings of the container 78 // It is for PID namespace setting. Usually different containers 79 // have their own PID namespace, however this specifies to use 80 // an existing PID namespace. 81 // Joining the host's PID namespace is currently the only supported 82 // option. 83 type Pid struct { 84 HostPid bool `json:"host_pid"` 85 } 86 87 // UTS settings of the container 88 // It is for UTS namespace setting. Usually different containers 89 // have their own UTS namespace, however this specifies to use 90 // an existing UTS namespace. 91 // Joining the host's UTS namespace is currently the only supported 92 // option. 93 type UTS struct { 94 HostUTS bool `json:"host_uts"` 95 } 96 97 // Network settings of the container 98 type Network struct { 99 Mtu int `json:"mtu"` 100 ContainerID string `json:"container_id"` // id of the container to join network. 101 NamespacePath string `json:"namespace_path"` 102 HostNetworking bool `json:"host_networking"` 103 } 104 105 // Command wraps an os/exec.Cmd to add more metadata 106 type Command struct { 107 CommonCommand 108 109 // Fields below here are platform specific 110 111 AllowedDevices []*configs.Device `json:"allowed_devices"` 112 AppArmorProfile string `json:"apparmor_profile"` 113 AutoCreatedDevices []*configs.Device `json:"autocreated_devices"` 114 CapAdd []string `json:"cap_add"` 115 CapDrop []string `json:"cap_drop"` 116 CgroupParent string `json:"cgroup_parent"` // The parent cgroup for this command. 117 GIDMapping []idtools.IDMap `json:"gidmapping"` 118 GroupAdd []string `json:"group_add"` 119 Ipc *Ipc `json:"ipc"` 120 OomScoreAdj int `json:"oom_score_adj"` 121 Pid *Pid `json:"pid"` 122 ReadonlyRootfs bool `json:"readonly_rootfs"` 123 RemappedRoot *User `json:"remap_root"` 124 SeccompProfile string `json:"seccomp_profile"` 125 UIDMapping []idtools.IDMap `json:"uidmapping"` 126 UTS *UTS `json:"uts"` 127 } 128 129 // SetRootPropagation sets the root mount propagation mode. 130 func SetRootPropagation(config *configs.Config, propagation int) { 131 config.RootPropagation = propagation 132 } 133 134 // InitContainer is the initialization of a container config. 135 // It returns the initial configs for a container. It's mostly 136 // defined by the default template. 137 func InitContainer(c *Command) *configs.Config { 138 container := template.New() 139 140 container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env) 141 container.Cgroups.Name = c.ID 142 container.Cgroups.Resources.AllowedDevices = c.AllowedDevices 143 container.Devices = c.AutoCreatedDevices 144 container.Rootfs = c.Rootfs 145 container.Readonlyfs = c.ReadonlyRootfs 146 // This can be overridden later by driver during mount setup based 147 // on volume options 148 SetRootPropagation(container, mount.RPRIVATE) 149 container.Cgroups.Parent = c.CgroupParent 150 151 // check to see if we are running in ramdisk to disable pivot root 152 container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" 153 154 return container 155 } 156 157 func getEnv(key string, env []string) string { 158 for _, pair := range env { 159 parts := strings.SplitN(pair, "=", 2) 160 if parts[0] == key { 161 return parts[1] 162 } 163 } 164 return "" 165 } 166 167 // SetupCgroups setups cgroup resources for a container. 168 func SetupCgroups(container *configs.Config, c *Command) error { 169 if c.Resources != nil { 170 container.Cgroups.Resources.CpuShares = c.Resources.CPUShares 171 container.Cgroups.Resources.Memory = c.Resources.Memory 172 container.Cgroups.Resources.MemoryReservation = c.Resources.MemoryReservation 173 container.Cgroups.Resources.MemorySwap = c.Resources.MemorySwap 174 container.Cgroups.Resources.KernelMemory = c.Resources.KernelMemory 175 container.Cgroups.Resources.CpusetCpus = c.Resources.CpusetCpus 176 container.Cgroups.Resources.CpusetMems = c.Resources.CpusetMems 177 container.Cgroups.Resources.CpuPeriod = c.Resources.CPUPeriod 178 container.Cgroups.Resources.CpuQuota = c.Resources.CPUQuota 179 container.Cgroups.Resources.BlkioWeight = c.Resources.BlkioWeight 180 container.Cgroups.Resources.BlkioWeightDevice = c.Resources.BlkioWeightDevice 181 container.Cgroups.Resources.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice 182 container.Cgroups.Resources.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice 183 container.Cgroups.Resources.BlkioThrottleReadIOPSDevice = c.Resources.BlkioThrottleReadIOpsDevice 184 container.Cgroups.Resources.BlkioThrottleWriteIOPSDevice = c.Resources.BlkioThrottleWriteIOpsDevice 185 container.Cgroups.Resources.OomKillDisable = c.Resources.OomKillDisable 186 container.Cgroups.Resources.MemorySwappiness = c.Resources.MemorySwappiness 187 } 188 189 return nil 190 } 191 192 // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. 193 func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) { 194 out := &libcontainer.NetworkInterface{Name: interfaceName} 195 // This can happen if the network runtime information is missing - possible if the 196 // container was created by an old version of libcontainer. 197 if interfaceName == "" { 198 return out, nil 199 } 200 type netStatsPair struct { 201 // Where to write the output. 202 Out *uint64 203 // The network stats file to read. 204 File string 205 } 206 // Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container. 207 netStats := []netStatsPair{ 208 {Out: &out.RxBytes, File: "tx_bytes"}, 209 {Out: &out.RxPackets, File: "tx_packets"}, 210 {Out: &out.RxErrors, File: "tx_errors"}, 211 {Out: &out.RxDropped, File: "tx_dropped"}, 212 213 {Out: &out.TxBytes, File: "rx_bytes"}, 214 {Out: &out.TxPackets, File: "rx_packets"}, 215 {Out: &out.TxErrors, File: "rx_errors"}, 216 {Out: &out.TxDropped, File: "rx_dropped"}, 217 } 218 for _, netStat := range netStats { 219 data, err := readSysfsNetworkStats(interfaceName, netStat.File) 220 if err != nil { 221 return nil, err 222 } 223 *(netStat.Out) = data 224 } 225 return out, nil 226 } 227 228 // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics 229 func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { 230 data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) 231 if err != nil { 232 return 0, err 233 } 234 return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) 235 } 236 237 // Stats collects all the resource usage information from a container. 238 func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) { 239 f, err := os.Open(filepath.Join(containerDir, "state.json")) 240 if err != nil { 241 return nil, err 242 } 243 defer f.Close() 244 245 type network struct { 246 Type string 247 HostInterfaceName string 248 } 249 250 state := struct { 251 CgroupPaths map[string]string `json:"cgroup_paths"` 252 Networks []network 253 }{} 254 255 if err := json.NewDecoder(f).Decode(&state); err != nil { 256 return nil, err 257 } 258 now := time.Now() 259 260 mgr := fs.Manager{Paths: state.CgroupPaths} 261 cstats, err := mgr.GetStats() 262 if err != nil { 263 return nil, err 264 } 265 stats := &libcontainer.Stats{CgroupStats: cstats} 266 // if the container does not have any memory limit specified set the 267 // limit to the machines memory 268 memoryLimit := containerMemoryLimit 269 if memoryLimit == 0 { 270 memoryLimit = machineMemory 271 } 272 for _, iface := range state.Networks { 273 switch iface.Type { 274 case "veth": 275 istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) 276 if err != nil { 277 return nil, err 278 } 279 stats.Interfaces = append(stats.Interfaces, istats) 280 } 281 } 282 return &ResourceStats{ 283 Stats: stats, 284 Read: now, 285 MemoryLimit: memoryLimit, 286 }, nil 287 } 288 289 // User contains the uid and gid representing a Unix user 290 type User struct { 291 UID int `json:"root_uid"` 292 GID int `json:"root_gid"` 293 } 294 295 // ExitStatus provides exit reasons for a container. 296 type ExitStatus struct { 297 // The exit code with which the container exited. 298 ExitCode int 299 300 // Whether the container encountered an OOM. 301 OOMKilled bool 302 }