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  }