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