github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/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/opencontainers/runc/libcontainer" 16 "github.com/opencontainers/runc/libcontainer/cgroups/fs" 17 "github.com/opencontainers/runc/libcontainer/configs" 18 ) 19 20 // Network settings of the container 21 type Network struct { 22 Mtu int `json:"mtu"` 23 ContainerID string `json:"container_id"` // id of the container to join network. 24 NamespacePath string `json:"namespace_path"` 25 HostNetworking bool `json:"host_networking"` 26 } 27 28 // InitContainer is the initialization of a container config. 29 // It returns the initial configs for a container. It's mostly 30 // defined by the default template. 31 func InitContainer(c *Command) *configs.Config { 32 container := template.New() 33 34 container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env) 35 container.Cgroups.Name = c.ID 36 container.Cgroups.AllowedDevices = c.AllowedDevices 37 container.Devices = c.AutoCreatedDevices 38 container.Rootfs = c.Rootfs 39 container.Readonlyfs = c.ReadonlyRootfs 40 container.Privatefs = true 41 42 // check to see if we are running in ramdisk to disable pivot root 43 container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" 44 45 // Default parent cgroup is "docker". Override if required. 46 if c.CgroupParent != "" { 47 container.Cgroups.Parent = c.CgroupParent 48 } 49 return container 50 } 51 52 func getEnv(key string, env []string) string { 53 for _, pair := range env { 54 parts := strings.SplitN(pair, "=", 2) 55 if parts[0] == key { 56 return parts[1] 57 } 58 } 59 return "" 60 } 61 62 // SetupCgroups setups cgroup resources for a container. 63 func SetupCgroups(container *configs.Config, c *Command) error { 64 if c.Resources != nil { 65 container.Cgroups.CpuShares = c.Resources.CPUShares 66 container.Cgroups.Memory = c.Resources.Memory 67 container.Cgroups.MemoryReservation = c.Resources.Memory 68 container.Cgroups.MemorySwap = c.Resources.MemorySwap 69 container.Cgroups.CpusetCpus = c.Resources.CpusetCpus 70 container.Cgroups.CpusetMems = c.Resources.CpusetMems 71 container.Cgroups.CpuPeriod = c.Resources.CPUPeriod 72 container.Cgroups.CpuQuota = c.Resources.CPUQuota 73 container.Cgroups.BlkioWeight = c.Resources.BlkioWeight 74 container.Cgroups.OomKillDisable = c.Resources.OomKillDisable 75 container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness 76 } 77 78 return nil 79 } 80 81 // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. 82 func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) { 83 out := &libcontainer.NetworkInterface{Name: interfaceName} 84 // This can happen if the network runtime information is missing - possible if the 85 // container was created by an old version of libcontainer. 86 if interfaceName == "" { 87 return out, nil 88 } 89 type netStatsPair struct { 90 // Where to write the output. 91 Out *uint64 92 // The network stats file to read. 93 File string 94 } 95 // 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. 96 netStats := []netStatsPair{ 97 {Out: &out.RxBytes, File: "tx_bytes"}, 98 {Out: &out.RxPackets, File: "tx_packets"}, 99 {Out: &out.RxErrors, File: "tx_errors"}, 100 {Out: &out.RxDropped, File: "tx_dropped"}, 101 102 {Out: &out.TxBytes, File: "rx_bytes"}, 103 {Out: &out.TxPackets, File: "rx_packets"}, 104 {Out: &out.TxErrors, File: "rx_errors"}, 105 {Out: &out.TxDropped, File: "rx_dropped"}, 106 } 107 for _, netStat := range netStats { 108 data, err := readSysfsNetworkStats(interfaceName, netStat.File) 109 if err != nil { 110 return nil, err 111 } 112 *(netStat.Out) = data 113 } 114 return out, nil 115 } 116 117 // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics 118 func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { 119 data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) 120 if err != nil { 121 return 0, err 122 } 123 return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) 124 } 125 126 // Stats collects all the resource usage information from a container. 127 func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) { 128 f, err := os.Open(filepath.Join(containerDir, "state.json")) 129 if err != nil { 130 return nil, err 131 } 132 defer f.Close() 133 134 type network struct { 135 Type string 136 HostInterfaceName string 137 } 138 139 state := struct { 140 CgroupPaths map[string]string `json:"cgroup_paths"` 141 Networks []network 142 }{} 143 144 if err := json.NewDecoder(f).Decode(&state); err != nil { 145 return nil, err 146 } 147 now := time.Now() 148 149 mgr := fs.Manager{Paths: state.CgroupPaths} 150 cstats, err := mgr.GetStats() 151 if err != nil { 152 return nil, err 153 } 154 stats := &libcontainer.Stats{CgroupStats: cstats} 155 // if the container does not have any memory limit specified set the 156 // limit to the machines memory 157 memoryLimit := containerMemoryLimit 158 if memoryLimit == 0 { 159 memoryLimit = machineMemory 160 } 161 for _, iface := range state.Networks { 162 switch iface.Type { 163 case "veth": 164 istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) 165 if err != nil { 166 return nil, err 167 } 168 stats.Interfaces = append(stats.Interfaces, istats) 169 } 170 } 171 return &ResourceStats{ 172 Stats: stats, 173 Read: now, 174 MemoryLimit: memoryLimit, 175 }, nil 176 }