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