github.com/circular-dark/docker@v1.7.0/daemon/execdriver/driver_linux.go (about)

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