github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/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/idtools"
    16  	"github.com/docker/docker/pkg/mount"
    17  	"github.com/docker/go-units"
    18  	"github.com/opencontainers/runc/libcontainer"
    19  	"github.com/opencontainers/runc/libcontainer/cgroups/fs"
    20  	"github.com/opencontainers/runc/libcontainer/configs"
    21  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    22  )
    23  
    24  // Mount contains information for a mount operation.
    25  type Mount struct {
    26  	Source      string `json:"source"`
    27  	Destination string `json:"destination"`
    28  	Writable    bool   `json:"writable"`
    29  	Data        string `json:"data"`
    30  	Propagation string `json:"mountpropagation"`
    31  }
    32  
    33  // Resources contains all resource configs for a driver.
    34  // Currently these are all for cgroup configs.
    35  type Resources struct {
    36  	CommonResources
    37  
    38  	// Fields below here are platform specific
    39  
    40  	BlkioWeightDevice            []*blkiodev.WeightDevice   `json:"blkio_weight_device"`
    41  	BlkioThrottleReadBpsDevice   []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"`
    42  	BlkioThrottleWriteBpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"`
    43  	BlkioThrottleReadIOpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_iops_device"`
    44  	BlkioThrottleWriteIOpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_iops_device"`
    45  	MemorySwap                   int64                      `json:"memory_swap"`
    46  	KernelMemory                 int64                      `json:"kernel_memory"`
    47  	CPUQuota                     int64                      `json:"cpu_quota"`
    48  	CpusetCpus                   string                     `json:"cpuset_cpus"`
    49  	CpusetMems                   string                     `json:"cpuset_mems"`
    50  	CPUPeriod                    int64                      `json:"cpu_period"`
    51  	Rlimits                      []*units.Rlimit            `json:"rlimits"`
    52  	OomKillDisable               bool                       `json:"oom_kill_disable"`
    53  	PidsLimit                    int64                      `json:"pids_limit"`
    54  	MemorySwappiness             int64                      `json:"memory_swappiness"`
    55  }
    56  
    57  // ProcessConfig is the platform specific structure that describes a process
    58  // that will be run inside a container.
    59  type ProcessConfig struct {
    60  	CommonProcessConfig
    61  
    62  	// Fields below here are platform specific
    63  	Privileged bool   `json:"privileged"`
    64  	User       string `json:"user"`
    65  	Console    string `json:"-"` // dev/console path
    66  }
    67  
    68  // Ipc settings of the container
    69  // It is for IPC namespace setting. Usually different containers
    70  // have their own IPC namespace, however this specifies to use
    71  // an existing IPC namespace.
    72  // You can join the host's or a container's IPC namespace.
    73  type Ipc struct {
    74  	ContainerID string `json:"container_id"` // id of the container to join ipc.
    75  	HostIpc     bool   `json:"host_ipc"`
    76  }
    77  
    78  // Pid settings of the container
    79  // It is for PID namespace setting. Usually different containers
    80  // have their own PID namespace, however this specifies to use
    81  // an existing PID namespace.
    82  // Joining the host's PID namespace is currently the only supported
    83  // option.
    84  type Pid struct {
    85  	HostPid bool `json:"host_pid"`
    86  }
    87  
    88  // UTS settings of the container
    89  // It is for UTS namespace setting. Usually different containers
    90  // have their own UTS namespace, however this specifies to use
    91  // an existing UTS namespace.
    92  // Joining the host's UTS namespace is currently the only supported
    93  // option.
    94  type UTS struct {
    95  	HostUTS bool `json:"host_uts"`
    96  }
    97  
    98  // Network settings of the container
    99  type Network struct {
   100  	Mtu            int    `json:"mtu"`
   101  	ContainerID    string `json:"container_id"` // id of the container to join network.
   102  	NamespacePath  string `json:"namespace_path"`
   103  	HostNetworking bool   `json:"host_networking"`
   104  }
   105  
   106  // Command wraps an os/exec.Cmd to add more metadata
   107  type Command struct {
   108  	CommonCommand
   109  
   110  	// Fields below here are platform specific
   111  
   112  	AllowedDevices     []*configs.Device `json:"allowed_devices"`
   113  	AppArmorProfile    string            `json:"apparmor_profile"`
   114  	AutoCreatedDevices []*configs.Device `json:"autocreated_devices"`
   115  	CapAdd             []string          `json:"cap_add"`
   116  	CapDrop            []string          `json:"cap_drop"`
   117  	CgroupParent       string            `json:"cgroup_parent"` // The parent cgroup for this command.
   118  	GIDMapping         []idtools.IDMap   `json:"gidmapping"`
   119  	GroupAdd           []string          `json:"group_add"`
   120  	Ipc                *Ipc              `json:"ipc"`
   121  	OomScoreAdj        int               `json:"oom_score_adj"`
   122  	Pid                *Pid              `json:"pid"`
   123  	ReadonlyRootfs     bool              `json:"readonly_rootfs"`
   124  	RemappedRoot       *User             `json:"remap_root"`
   125  	SeccompProfile     string            `json:"seccomp_profile"`
   126  	UIDMapping         []idtools.IDMap   `json:"uidmapping"`
   127  	UTS                *UTS              `json:"uts"`
   128  	NoNewPrivileges    bool              `json:"no_new_privileges"`
   129  }
   130  
   131  // SetRootPropagation sets the root mount propagation mode.
   132  func SetRootPropagation(config *configs.Config, propagation int) {
   133  	config.RootPropagation = propagation
   134  }
   135  
   136  // InitContainer is the initialization of a container config.
   137  // It returns the initial configs for a container. It's mostly
   138  // defined by the default template.
   139  func InitContainer(c *Command) *configs.Config {
   140  	container := template.New()
   141  
   142  	container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
   143  	container.Cgroups.Name = c.ID
   144  	container.Cgroups.Resources.AllowedDevices = c.AllowedDevices
   145  	container.Devices = filterDevices(c.AutoCreatedDevices, (c.RemappedRoot.UID != 0))
   146  	container.Rootfs = c.Rootfs
   147  	container.Readonlyfs = c.ReadonlyRootfs
   148  	// This can be overridden later by driver during mount setup based
   149  	// on volume options
   150  	SetRootPropagation(container, mount.RPRIVATE)
   151  	container.Cgroups.Parent = c.CgroupParent
   152  
   153  	// check to see if we are running in ramdisk to disable pivot root
   154  	container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
   155  
   156  	return container
   157  }
   158  
   159  func filterDevices(devices []*configs.Device, userNamespacesEnabled bool) []*configs.Device {
   160  	if !userNamespacesEnabled {
   161  		return devices
   162  	}
   163  
   164  	filtered := []*configs.Device{}
   165  	// if we have user namespaces enabled, these devices will not be created
   166  	// because of the mknod limitation in the kernel for an unprivileged process.
   167  	// Rather, they will be bind-mounted, which will only work if they exist;
   168  	// check for existence and remove non-existent entries from the list
   169  	for _, device := range devices {
   170  		if _, err := os.Stat(device.Path); err == nil {
   171  			filtered = append(filtered, device)
   172  		}
   173  	}
   174  	return filtered
   175  }
   176  
   177  func getEnv(key string, env []string) string {
   178  	for _, pair := range env {
   179  		parts := strings.SplitN(pair, "=", 2)
   180  		if parts[0] == key {
   181  			return parts[1]
   182  		}
   183  	}
   184  	return ""
   185  }
   186  
   187  // SetupCgroups setups cgroup resources for a container.
   188  func SetupCgroups(container *configs.Config, c *Command) error {
   189  	if c.Resources != nil {
   190  		container.Cgroups.Resources.CpuShares = c.Resources.CPUShares
   191  		container.Cgroups.Resources.Memory = c.Resources.Memory
   192  		container.Cgroups.Resources.MemoryReservation = c.Resources.MemoryReservation
   193  		container.Cgroups.Resources.MemorySwap = c.Resources.MemorySwap
   194  		container.Cgroups.Resources.KernelMemory = c.Resources.KernelMemory
   195  		container.Cgroups.Resources.CpusetCpus = c.Resources.CpusetCpus
   196  		container.Cgroups.Resources.CpusetMems = c.Resources.CpusetMems
   197  		container.Cgroups.Resources.CpuPeriod = c.Resources.CPUPeriod
   198  		container.Cgroups.Resources.CpuQuota = c.Resources.CPUQuota
   199  		container.Cgroups.Resources.BlkioWeight = c.Resources.BlkioWeight
   200  		container.Cgroups.Resources.BlkioWeightDevice = c.Resources.BlkioWeightDevice
   201  		container.Cgroups.Resources.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice
   202  		container.Cgroups.Resources.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice
   203  		container.Cgroups.Resources.BlkioThrottleReadIOPSDevice = c.Resources.BlkioThrottleReadIOpsDevice
   204  		container.Cgroups.Resources.BlkioThrottleWriteIOPSDevice = c.Resources.BlkioThrottleWriteIOpsDevice
   205  		container.Cgroups.Resources.OomKillDisable = c.Resources.OomKillDisable
   206  		container.Cgroups.Resources.PidsLimit = c.Resources.PidsLimit
   207  		container.Cgroups.Resources.MemorySwappiness = c.Resources.MemorySwappiness
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
   214  func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) {
   215  	out := &libcontainer.NetworkInterface{Name: interfaceName}
   216  	// This can happen if the network runtime information is missing - possible if the
   217  	// container was created by an old version of libcontainer.
   218  	if interfaceName == "" {
   219  		return out, nil
   220  	}
   221  	type netStatsPair struct {
   222  		// Where to write the output.
   223  		Out *uint64
   224  		// The network stats file to read.
   225  		File string
   226  	}
   227  	// 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.
   228  	netStats := []netStatsPair{
   229  		{Out: &out.RxBytes, File: "tx_bytes"},
   230  		{Out: &out.RxPackets, File: "tx_packets"},
   231  		{Out: &out.RxErrors, File: "tx_errors"},
   232  		{Out: &out.RxDropped, File: "tx_dropped"},
   233  
   234  		{Out: &out.TxBytes, File: "rx_bytes"},
   235  		{Out: &out.TxPackets, File: "rx_packets"},
   236  		{Out: &out.TxErrors, File: "rx_errors"},
   237  		{Out: &out.TxDropped, File: "rx_dropped"},
   238  	}
   239  	for _, netStat := range netStats {
   240  		data, err := readSysfsNetworkStats(interfaceName, netStat.File)
   241  		if err != nil {
   242  			return nil, err
   243  		}
   244  		*(netStat.Out) = data
   245  	}
   246  	return out, nil
   247  }
   248  
   249  // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
   250  func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
   251  	data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
   252  	if err != nil {
   253  		return 0, err
   254  	}
   255  	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
   256  }
   257  
   258  // Stats collects all the resource usage information from a container.
   259  func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
   260  	f, err := os.Open(filepath.Join(containerDir, "state.json"))
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  	defer f.Close()
   265  
   266  	type network struct {
   267  		Type              string
   268  		HostInterfaceName string
   269  	}
   270  
   271  	state := struct {
   272  		CgroupPaths map[string]string `json:"cgroup_paths"`
   273  		Networks    []network
   274  	}{}
   275  
   276  	if err := json.NewDecoder(f).Decode(&state); err != nil {
   277  		return nil, err
   278  	}
   279  	now := time.Now()
   280  
   281  	mgr := fs.Manager{Paths: state.CgroupPaths}
   282  	cstats, err := mgr.GetStats()
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	stats := &libcontainer.Stats{CgroupStats: cstats}
   287  	// if the container does not have any memory limit specified set the
   288  	// limit to the machines memory
   289  	memoryLimit := containerMemoryLimit
   290  	if memoryLimit == 0 {
   291  		memoryLimit = machineMemory
   292  	}
   293  	for _, iface := range state.Networks {
   294  		switch iface.Type {
   295  		case "veth":
   296  			istats, err := getNetworkInterfaceStats(iface.HostInterfaceName)
   297  			if err != nil {
   298  				return nil, err
   299  			}
   300  			stats.Interfaces = append(stats.Interfaces, istats)
   301  		}
   302  	}
   303  	return &ResourceStats{
   304  		Stats:       stats,
   305  		Read:        now,
   306  		MemoryLimit: memoryLimit,
   307  	}, nil
   308  }
   309  
   310  // User contains the uid and gid representing a Unix user
   311  type User struct {
   312  	UID int `json:"root_uid"`
   313  	GID int `json:"root_gid"`
   314  }
   315  
   316  // ExitStatus provides exit reasons for a container.
   317  type ExitStatus struct {
   318  	// The exit code with which the container exited.
   319  	ExitCode int
   320  
   321  	// Whether the container encountered an OOM.
   322  	OOMKilled bool
   323  }