diff --git a/daemon/container_unix.go b/daemon/container_unix.go index b5163a1110..4bc0c71279 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -272,11 +272,11 @@ func populateCommand(c *Container, env []string) error { resources := &execdriver.Resources{ Memory: c.hostConfig.Memory, MemorySwap: c.hostConfig.MemorySwap, - CpuShares: c.hostConfig.CPUShares, + CPUShares: c.hostConfig.CPUShares, CpusetCpus: c.hostConfig.CpusetCpus, CpusetMems: c.hostConfig.CpusetMems, - CpuPeriod: c.hostConfig.CPUPeriod, - CpuQuota: c.hostConfig.CPUQuota, + CPUPeriod: c.hostConfig.CPUPeriod, + CPUQuota: c.hostConfig.CPUQuota, BlkioWeight: c.hostConfig.BlkioWeight, Rlimits: rlimits, OomKillDisable: c.hostConfig.OomKillDisable, diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index bd2e24cd08..61cf024a57 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -16,6 +16,7 @@ import ( // arbatrary data to be sent type Context map[string]string +// Define error messages var ( ErrNotRunning = errors.New("Container is not running") ErrWaitTimeoutReached = errors.New("Wait timeout reached") @@ -23,17 +24,19 @@ var ( ErrDriverNotFound = errors.New("The requested docker init has not been found") ) +// StartCallback defines a callback function. +// It's used by 'Run' and 'Exec', does some work in parent process +// after child process is started. type StartCallback func(*ProcessConfig, int) -// Driver specific information based on +// Info is driver specific information based on // processes registered with the driver type Info interface { IsRunning() bool } -// Terminal in an interface for drivers to implement -// if they want to support Close and Resize calls from -// the core +// Terminal represents a pseudo TTY, it is for when +// using a container interactively. type Terminal interface { io.Closer Resize(height, width int) error @@ -48,19 +51,44 @@ type ExitStatus struct { OOMKilled bool } +// Driver is an interface for drivers to implement +// including all basic functions a driver should have type Driver interface { - Run(c *Command, pipes *Pipes, startCallback StartCallback) (ExitStatus, error) // Run executes the process and blocks until the process exits and returns the exit code - // Exec executes the process in an existing container, blocks until the process exits and returns the exit code + // Run executes the process, blocks until the process exits and returns + // the exit code. It's the last stage on Docker side for running a container. + Run(c *Command, pipes *Pipes, startCallback StartCallback) (ExitStatus, error) + + // Exec executes the process in an existing container, blocks until the + // process exits and returns the exit code. Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, startCallback StartCallback) (int, error) + + // Kill sends signals to process in container. Kill(c *Command, sig int) error + + // Pause pauses a container. Pause(c *Command) error + + // Unpause unpauses a container. Unpause(c *Command) error - Name() string // Driver name - Info(id string) Info // "temporary" hack (until we move state from core to plugins) - GetPidsForContainer(id string) ([]int, error) // Returns a list of pids for the given container. - Terminate(c *Command) error // kill it with fire - Clean(id string) error // clean all traces of container exec - Stats(id string) (*ResourceStats, error) // Get resource stats for a running container + + // Name returns the name of the driver. + Name() string + + // Info returns the configuration stored in the driver struct, + // "temporary" hack (until we move state from core to plugins). + Info(id string) Info + + // GetPidsForContainer returns a list of pid for the processes running in a container. + GetPidsForContainer(id string) ([]int, error) + + // Terminate kills a container by sending signal SIGKILL. + Terminate(c *Command) error + + // Clean removes all traces of container exec. + Clean(id string) error + + // Stats returns resource stats for a running container + Stats(id string) (*ResourceStats, error) } // Network settings of the container @@ -72,22 +100,37 @@ type Network struct { HostNetworking bool `json:"host_networking"` } -// IPC settings of the container +// Ipc settings of the container +// It is for IPC namespace setting. Usually different containers +// have their own IPC namespace, however this specifies to use +// an existing IPC namespace. +// You can join the host's or a container's IPC namespace. type Ipc struct { ContainerID string `json:"container_id"` // id of the container to join ipc. HostIpc bool `json:"host_ipc"` } -// PID settings of the container +// Pid settings of the container +// It is for PID namespace setting. Usually different containers +// have their own PID namespace, however this specifies to use +// an existing PID namespace. +// Joining the host's PID namespace is currently the only supported +// option. type Pid struct { HostPid bool `json:"host_pid"` } // UTS settings of the container +// It is for UTS namespace setting. Usually different containers +// have their own UTS namespace, however this specifies to use +// an existing UTS namespace. +// Joining the host's UTS namespace is currently the only supported +// option. type UTS struct { HostUTS bool `json:"host_uts"` } +// NetworkInterface contains all network configs for a driver type NetworkInterface struct { Gateway string `json:"gateway"` IPAddress string `json:"ip"` @@ -101,21 +144,24 @@ type NetworkInterface struct { HairpinMode bool `json:"hairpin_mode"` } +// Resources contains all resource configs for a driver. +// Currently these are all for cgroup configs. // TODO Windows: Factor out ulimit.Rlimit type Resources struct { Memory int64 `json:"memory"` MemorySwap int64 `json:"memory_swap"` - CpuShares int64 `json:"cpu_shares"` + CPUShares int64 `json:"cpu_shares"` CpusetCpus string `json:"cpuset_cpus"` CpusetMems string `json:"cpuset_mems"` - CpuPeriod int64 `json:"cpu_period"` - CpuQuota int64 `json:"cpu_quota"` + CPUPeriod int64 `json:"cpu_period"` + CPUQuota int64 `json:"cpu_quota"` BlkioWeight int64 `json:"blkio_weight"` Rlimits []*ulimit.Rlimit `json:"rlimits"` OomKillDisable bool `json:"oom_kill_disable"` MemorySwappiness int64 `json:"memory_swappiness"` } +// ResourceStats contains information about resource usage by a container. type ResourceStats struct { *libcontainer.Stats Read time.Time `json:"read"` @@ -123,6 +169,7 @@ type ResourceStats struct { SystemUsage uint64 `json:"system_usage"` } +// Mount contains information for a mount operation. type Mount struct { Source string `json:"source"` Destination string `json:"destination"` @@ -131,7 +178,7 @@ type Mount struct { Slave bool `json:"slave"` } -// Describes a process that will be run inside a container. +// ProcessConfig describes a process that will be run inside a container. type ProcessConfig struct { exec.Cmd `json:"-"` @@ -145,10 +192,10 @@ type ProcessConfig struct { ConsoleSize [2]int `json:"-"` // h,w of initial console size } +// Command wrapps an os/exec.Cmd to add more metadata +// // TODO Windows: Factor out unused fields such as LxcConfig, AppArmorProfile, // and CgroupParent. -// -// Process wrapps an os/exec.Cmd to add more metadata type Command struct { ID string `json:"id"` Rootfs string `json:"rootfs"` // root fs of the container diff --git a/daemon/execdriver/driver_linux.go b/daemon/execdriver/driver_linux.go index 484c5f5ebe..4c4f63156e 100644 --- a/daemon/execdriver/driver_linux.go +++ b/daemon/execdriver/driver_linux.go @@ -15,6 +15,9 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" ) +// InitContainer is the initialization of a container config. +// It returns the initial configs for a container. It's mostly +// defined by the default template. func InitContainer(c *Command) *configs.Config { container := template.New() @@ -46,16 +49,17 @@ func getEnv(key string, env []string) string { return "" } +// SetupCgroups setups cgroup resources for a container. func SetupCgroups(container *configs.Config, c *Command) error { if c.Resources != nil { - container.Cgroups.CpuShares = c.Resources.CpuShares + container.Cgroups.CpuShares = c.Resources.CPUShares container.Cgroups.Memory = c.Resources.Memory container.Cgroups.MemoryReservation = c.Resources.Memory container.Cgroups.MemorySwap = c.Resources.MemorySwap container.Cgroups.CpusetCpus = c.Resources.CpusetCpus container.Cgroups.CpusetMems = c.Resources.CpusetMems - container.Cgroups.CpuPeriod = c.Resources.CpuPeriod - container.Cgroups.CpuQuota = c.Resources.CpuQuota + container.Cgroups.CpuPeriod = c.Resources.CPUPeriod + container.Cgroups.CpuQuota = c.Resources.CPUQuota container.Cgroups.BlkioWeight = c.Resources.BlkioWeight container.Cgroups.OomKillDisable = c.Resources.OomKillDisable container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness @@ -109,6 +113,7 @@ func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) } +// Stats collects all the resource usage information from a container. func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) { f, err := os.Open(filepath.Join(containerDir, "state.json")) if err != nil { diff --git a/daemon/execdriver/execdrivers/execdrivers_linux.go b/daemon/execdriver/execdrivers/execdrivers_linux.go index 89dedc762e..e7b2be4160 100644 --- a/daemon/execdriver/execdrivers/execdrivers_linux.go +++ b/daemon/execdriver/execdrivers/execdrivers_linux.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/pkg/sysinfo" ) +// NewDriver returns a new execdriver.Driver from the given name configured with the provided options. func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) { switch name { case "lxc": diff --git a/daemon/execdriver/execdrivers/execdrivers_windows.go b/daemon/execdriver/execdrivers/execdrivers_windows.go index d169b900af..a043ff7b0b 100644 --- a/daemon/execdriver/execdrivers/execdrivers_windows.go +++ b/daemon/execdriver/execdrivers/execdrivers_windows.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/pkg/sysinfo" ) +// NewDriver returns a new execdriver.Driver from the given name configured with the provided options. func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) { switch name { case "windows": diff --git a/daemon/execdriver/lxc/driver.go b/daemon/execdriver/lxc/driver.go index a3a9e0c6c8..27da7c8c24 100644 --- a/daemon/execdriver/lxc/driver.go +++ b/daemon/execdriver/lxc/driver.go @@ -34,11 +34,15 @@ import ( "github.com/vishvananda/netns" ) +// DriverName for lxc driver const DriverName = "lxc" +// ErrExec defines unsupported error message var ErrExec = errors.New("Unsupported: Exec is not supported by the lxc driver") -type driver struct { +// Driver contains all information for lxc driver, +// it implements execdriver.Driver +type Driver struct { root string // root path for the driver to use libPath string initPath string @@ -54,7 +58,8 @@ type activeContainer struct { cmd *exec.Cmd } -func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) { +// NewDriver returns a new lxc driver, called from NewDriver of execdriver +func NewDriver(root, libPath, initPath string, apparmor bool) (*Driver, error) { if err := os.MkdirAll(root, 0700); err != nil { return nil, err } @@ -66,7 +71,7 @@ func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) { if err != nil { return nil, err } - return &driver{ + return &Driver{ apparmor: apparmor, root: root, libPath: libPath, @@ -77,7 +82,8 @@ func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) { }, nil } -func (d *driver) Name() string { +// Name implements the exec driver Driver interface. +func (d *Driver) Name() string { version := d.version() return fmt.Sprintf("%s-%s", DriverName, version) } @@ -117,7 +123,9 @@ func killNetNsProc(proc *os.Process) { proc.Wait() } -func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { +// Run implements the exec driver Driver interface, +// it calls 'exec.Cmd' to launch lxc commands to run a container. +func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { var ( term execdriver.Terminal err error @@ -392,7 +400,7 @@ func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) { // createContainer populates and configures the container type with the // data provided by the execdriver.Command -func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) { +func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) { container := execdriver.InitContainer(c) if err := execdriver.SetupCgroups(container, c); err != nil { return nil, err @@ -400,8 +408,8 @@ func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) return container, nil } -// Return an map of susbystem -> container cgroup -func cgroupPaths(containerId string) (map[string]string, error) { +// Return an map of susbystem -> absolute container cgroup path +func cgroupPaths(containerID string) (map[string]string, error) { subsystems, err := cgroups.GetAllSubsystems() if err != nil { return nil, err @@ -415,7 +423,7 @@ func cgroupPaths(containerId string) (map[string]string, error) { //unsupported subystem continue } - path := filepath.Join(cgroupRoot, cgroupDir, "lxc", containerId) + path := filepath.Join(cgroupRoot, cgroupDir, "lxc", containerID) paths[subsystem] = path } @@ -506,8 +514,8 @@ func setupUser(userSpec string) error { return nil } -/// Return the exit code of the process -// if the process has not exited -1 will be returned +// getExitCode returns the exit code of the process. +// If the process has not exited -1 will be returned. func getExitCode(c *execdriver.Command) int { if c.ProcessConfig.ProcessState == nil { return -1 @@ -515,15 +523,18 @@ func getExitCode(c *execdriver.Command) int { return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() } -func (d *driver) Kill(c *execdriver.Command, sig int) error { +// Kill implements the exec driver Driver interface. +func (d *Driver) Kill(c *execdriver.Command, sig int) error { if sig == 9 || c.ProcessConfig.Process == nil { - return KillLxc(c.ID, sig) + return killLxc(c.ID, sig) } return c.ProcessConfig.Process.Signal(syscall.Signal(sig)) } -func (d *driver) Pause(c *execdriver.Command) error { +// Pause implements the exec driver Driver interface, +// it executes lxc-freeze to pause a container. +func (d *Driver) Pause(c *execdriver.Command) error { _, err := exec.LookPath("lxc-freeze") if err == nil { output, errExec := exec.Command("lxc-freeze", "-n", c.ID).CombinedOutput() @@ -535,7 +546,9 @@ func (d *driver) Pause(c *execdriver.Command) error { return err } -func (d *driver) Unpause(c *execdriver.Command) error { +// Unpause implements the exec driver Driver interface, +// it executes lxc-unfreeze to unpause a container. +func (d *Driver) Unpause(c *execdriver.Command) error { _, err := exec.LookPath("lxc-unfreeze") if err == nil { output, errExec := exec.Command("lxc-unfreeze", "-n", c.ID).CombinedOutput() @@ -547,11 +560,12 @@ func (d *driver) Unpause(c *execdriver.Command) error { return err } -func (d *driver) Terminate(c *execdriver.Command) error { - return KillLxc(c.ID, 9) +// Terminate implements the exec driver Driver interface. +func (d *Driver) Terminate(c *execdriver.Command) error { + return killLxc(c.ID, 9) } -func (d *driver) version() string { +func (d *Driver) version() string { var ( version string output []byte @@ -571,7 +585,7 @@ func (d *driver) version() string { return version } -func KillLxc(id string, sig int) error { +func killLxc(id string, sig int) error { var ( err error output []byte @@ -590,7 +604,7 @@ func KillLxc(id string, sig int) error { } // wait for the process to start and return the pid for the process -func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) { +func (d *Driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) { var ( err error output []byte @@ -622,13 +636,13 @@ func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (in return -1, execdriver.ErrNotRunning } -func (d *driver) getInfo(id string) ([]byte, error) { +func (d *Driver) getInfo(id string) ([]byte, error) { return exec.Command("lxc-info", "-n", id).CombinedOutput() } type info struct { ID string - driver *driver + driver *Driver } func (i *info) IsRunning() bool { @@ -645,7 +659,8 @@ func (i *info) IsRunning() bool { return running } -func (d *driver) Info(id string) execdriver.Info { +// Info implements the exec driver Driver interface. +func (d *Driver) Info(id string) execdriver.Info { return &info{ ID: id, driver: d, @@ -665,7 +680,8 @@ func findCgroupRootAndDir(subsystem string) (string, string, error) { return cgroupRoot, cgroupDir, nil } -func (d *driver) GetPidsForContainer(id string) ([]int, error) { +// GetPidsForContainer implements the exec driver Driver interface. +func (d *Driver) GetPidsForContainer(id string) ([]int, error) { pids := []int{} // cpu is chosen because it is the only non optional subsystem in cgroups @@ -730,11 +746,11 @@ func rootIsShared() bool { return true } -func (d *driver) containerDir(containerId string) string { - return path.Join(d.libPath, "containers", containerId) +func (d *Driver) containerDir(containerID string) string { + return path.Join(d.libPath, "containers", containerID) } -func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) { +func (d *Driver) generateLXCConfig(c *execdriver.Command) (string, error) { root := path.Join(d.containerDir(c.ID), "config.lxc") fo, err := os.Create(root) @@ -743,7 +759,7 @@ func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) { } defer fo.Close() - if err := LxcTemplateCompiled.Execute(fo, struct { + if err := lxcTemplateCompiled.Execute(fo, struct { *execdriver.Command AppArmor bool }{ @@ -756,7 +772,7 @@ func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) { return root, nil } -func (d *driver) generateEnvConfig(c *execdriver.Command) error { +func (d *Driver) generateEnvConfig(c *execdriver.Command) error { data, err := json.Marshal(c.ProcessConfig.Env) if err != nil { return err @@ -772,16 +788,21 @@ func (d *driver) generateEnvConfig(c *execdriver.Command) error { return ioutil.WriteFile(p, data, 0600) } -// Clean not implemented for lxc -func (d *driver) Clean(id string) error { +// Clean implements the exec driver Driver interface, +// it's not implemented by lxc. +func (d *Driver) Clean(id string) error { return nil } +// TtyConsole implements the exec driver Terminal interface, +// it stores the master and slave ends of the container's pty. type TtyConsole struct { MasterPty *os.File SlavePty *os.File } +// NewTtyConsole returns a new TtyConsole struct. +// Wired up to the provided process config and stdin/stdout/stderr pipes. func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) { // lxc is special in that we cannot create the master outside of the container without // opening the slave because we have nothing to provide to the cmd. We have to open both then do @@ -808,10 +829,12 @@ func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pi return tty, nil } +// Resize implements Resize method of Terminal interface func (t *TtyConsole) Resize(h, w int) error { return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) } +// AttachPipes attaches given pipes to exec.Cmd func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error { command.Stdout = t.SlavePty command.Stderr = t.SlavePty @@ -839,16 +862,22 @@ func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) err return nil } +// Close implements Close method of Terminal interface func (t *TtyConsole) Close() error { t.SlavePty.Close() return t.MasterPty.Close() } -func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { +// Exec implements the exec driver Driver interface, +// it is not implemented by lxc. +func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { return -1, ErrExec } -func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) { +// Stats implements the exec driver Driver interface. +// Lxc doesn't implement it's own Stats, it does some trick by implementing +// execdriver.Stats to get stats info by libcontainer APIs. +func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) { if _, ok := d.activeContainers[id]; !ok { return nil, fmt.Errorf("%s is not a key in active containers", id) } diff --git a/daemon/execdriver/lxc/info.go b/daemon/execdriver/lxc/info.go index 279211f324..3a63091325 100644 --- a/daemon/execdriver/lxc/info.go +++ b/daemon/execdriver/lxc/info.go @@ -9,6 +9,7 @@ import ( "strings" ) +// Define error messages var ( ErrCannotParse = errors.New("cannot parse raw input") ) diff --git a/daemon/execdriver/lxc/init.go b/daemon/execdriver/lxc/init.go index aba1c74c26..da5d502088 100644 --- a/daemon/execdriver/lxc/init.go +++ b/daemon/execdriver/lxc/init.go @@ -16,11 +16,11 @@ import ( "github.com/docker/docker/pkg/reexec" ) -// Args provided to the init function for a driver +// InitArgs contains args provided to the init function for a driver type InitArgs struct { User string Gateway string - Ip string + IP string WorkDir string Privileged bool Env []string @@ -94,7 +94,7 @@ func getArgs() *InitArgs { return &InitArgs{ User: *user, Gateway: *gateway, - Ip: *ip, + IP: *ip, WorkDir: *workDir, Privileged: *privileged, Args: flag.Args(), diff --git a/daemon/execdriver/lxc/lxc_template.go b/daemon/execdriver/lxc/lxc_template.go index a4ac51ea62..74845398f1 100644 --- a/daemon/execdriver/lxc/lxc_template.go +++ b/daemon/execdriver/lxc/lxc_template.go @@ -15,6 +15,8 @@ import ( "github.com/opencontainers/runc/libcontainer/label" ) +// LxcTemplate is the template for lxc driver, it's used +// to configure LXC. const LxcTemplate = ` lxc.network.type = none # root filesystem @@ -94,11 +96,11 @@ lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}} lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}} {{end}} {{end}} -{{if .Resources.CpuShares}} -lxc.cgroup.cpu.shares = {{.Resources.CpuShares}} +{{if .Resources.CPUShares}} +lxc.cgroup.cpu.shares = {{.Resources.CPUShares}} {{end}} -{{if .Resources.CpuPeriod}} -lxc.cgroup.cpu.cfs_period_us = {{.Resources.CpuPeriod}} +{{if .Resources.CPUPeriod}} +lxc.cgroup.cpu.cfs_period_us = {{.Resources.CPUPeriod}} {{end}} {{if .Resources.CpusetCpus}} lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}} @@ -106,8 +108,8 @@ lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}} {{if .Resources.CpusetMems}} lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}} {{end}} -{{if .Resources.CpuQuota}} -lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CpuQuota}} +{{if .Resources.CPUQuota}} +lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CPUQuota}} {{end}} {{if .Resources.BlkioWeight}} lxc.cgroup.blkio.weight = {{.Resources.BlkioWeight}} @@ -158,7 +160,7 @@ lxc.cap.drop = {{.}} {{end}} ` -var LxcTemplateCompiled *template.Template +var lxcTemplateCompiled *template.Template // Escape spaces in strings according to the fstab documentation, which is the // format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab". @@ -254,7 +256,7 @@ func init() { "dropList": dropList, "getHostname": getHostname, } - LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate) + lxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate) if err != nil { panic(err) } diff --git a/daemon/execdriver/lxc/lxc_template_unit_test.go b/daemon/execdriver/lxc/lxc_template_unit_test.go index 2d4dba5c7f..5ef8f020c7 100644 --- a/daemon/execdriver/lxc/lxc_template_unit_test.go +++ b/daemon/execdriver/lxc/lxc_template_unit_test.go @@ -47,7 +47,7 @@ func TestLXCConfig(t *testing.T) { ID: "1", Resources: &execdriver.Resources{ Memory: int64(mem), - CpuShares: int64(cpu), + CPUShares: int64(cpu), }, Network: &execdriver.Network{ Mtu: 1500, diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index 0f0a6a12dc..c7fc33d1d5 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -18,7 +18,7 @@ import ( // createContainer populates and configures the container type with the // data provided by the execdriver.Command -func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) { +func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) { container := execdriver.InitContainer(c) if err := d.createIpc(container, c); err != nil { @@ -113,7 +113,7 @@ func generateIfaceName() (string, error) { return "", errors.New("Failed to find name for new interface") } -func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error { +func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command) error { if c.Network == nil { return nil } @@ -143,7 +143,7 @@ func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) return nil } -func (d *driver) createIpc(container *configs.Config, c *execdriver.Command) error { +func (d *Driver) createIpc(container *configs.Config, c *execdriver.Command) error { if c.Ipc.HostIpc { container.Namespaces.Remove(configs.NEWIPC) return nil @@ -168,7 +168,7 @@ func (d *driver) createIpc(container *configs.Config, c *execdriver.Command) err return nil } -func (d *driver) createPid(container *configs.Config, c *execdriver.Command) error { +func (d *Driver) createPid(container *configs.Config, c *execdriver.Command) error { if c.Pid.HostPid { container.Namespaces.Remove(configs.NEWPID) return nil @@ -177,7 +177,7 @@ func (d *driver) createPid(container *configs.Config, c *execdriver.Command) err return nil } -func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) error { +func (d *Driver) createUTS(container *configs.Config, c *execdriver.Command) error { if c.UTS.HostUTS { container.Namespaces.Remove(configs.NEWUTS) container.Hostname = "" @@ -187,7 +187,7 @@ func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) err return nil } -func (d *driver) setPrivileged(container *configs.Config) (err error) { +func (d *Driver) setPrivileged(container *configs.Config) (err error) { container.Capabilities = execdriver.GetAllCapabilities() container.Cgroups.AllowAllDevices = true @@ -204,12 +204,12 @@ func (d *driver) setPrivileged(container *configs.Config) (err error) { return nil } -func (d *driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) { +func (d *Driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) { container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) return err } -func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) { +func (d *Driver) setupRlimits(container *configs.Config, c *execdriver.Command) { if c.Resources == nil { return } @@ -223,7 +223,7 @@ func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) } } -func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error { +func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) error { userMounts := make(map[string]struct{}) for _, m := range c.Mounts { userMounts[m.Destination] = struct{}{} @@ -260,7 +260,7 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e return nil } -func (d *driver) setupLabels(container *configs.Config, c *execdriver.Command) { +func (d *Driver) setupLabels(container *configs.Config, c *execdriver.Command) { container.ProcessLabel = c.ProcessLabel container.MountLabel = c.MountLabel } diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index a94de3d18f..2dea93ade4 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -27,12 +27,15 @@ import ( "github.com/opencontainers/runc/libcontainer/utils" ) +// Define constants for native driver const ( DriverName = "native" Version = "0.2" ) -type driver struct { +// Driver contains all information for native driver, +// it implements execdriver.Driver. +type Driver struct { root string initPath string activeContainers map[string]libcontainer.Container @@ -41,7 +44,8 @@ type driver struct { sync.Mutex } -func NewDriver(root, initPath string, options []string) (*driver, error) { +// NewDriver returns a new native driver, called from NewDriver of execdriver. +func NewDriver(root, initPath string, options []string) (*Driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err @@ -96,7 +100,7 @@ func NewDriver(root, initPath string, options []string) (*driver, error) { return nil, err } - return &driver{ + return &Driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), @@ -110,7 +114,9 @@ type execOutput struct { err error } -func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { +// Run implements the exec driver Driver interface, +// it calls libcontainer APIs to run a container. +func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { // take the Command and populate the libcontainer.Config from it container, err := d.createContainer(c) if err != nil { @@ -238,7 +244,8 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o } } -func (d *driver) Kill(c *execdriver.Command, sig int) error { +// Kill implements the exec driver Driver interface. +func (d *Driver) Kill(c *execdriver.Command, sig int) error { d.Lock() active := d.activeContainers[c.ID] d.Unlock() @@ -252,7 +259,9 @@ func (d *driver) Kill(c *execdriver.Command, sig int) error { return syscall.Kill(state.InitProcessPid, syscall.Signal(sig)) } -func (d *driver) Pause(c *execdriver.Command) error { +// Pause implements the exec driver Driver interface, +// it calls libcontainer API to pause a container. +func (d *Driver) Pause(c *execdriver.Command) error { d.Lock() active := d.activeContainers[c.ID] d.Unlock() @@ -262,7 +271,9 @@ func (d *driver) Pause(c *execdriver.Command) error { return active.Pause() } -func (d *driver) Unpause(c *execdriver.Command) error { +// Unpause implements the exec driver Driver interface, +// it calls libcontainer API to unpause a container. +func (d *Driver) Unpause(c *execdriver.Command) error { d.Lock() active := d.activeContainers[c.ID] d.Unlock() @@ -272,7 +283,8 @@ func (d *driver) Unpause(c *execdriver.Command) error { return active.Resume() } -func (d *driver) Terminate(c *execdriver.Command) error { +// Terminate implements the exec driver Driver interface. +func (d *Driver) Terminate(c *execdriver.Command) error { defer d.cleanContainer(c.ID) container, err := d.factory.Load(c.ID) if err != nil { @@ -295,18 +307,21 @@ func (d *driver) Terminate(c *execdriver.Command) error { return err } -func (d *driver) Info(id string) execdriver.Info { +// Info implements the exec driver Driver interface. +func (d *Driver) Info(id string) execdriver.Info { return &info{ ID: id, driver: d, } } -func (d *driver) Name() string { +// Name implements the exec driver Driver interface. +func (d *Driver) Name() string { return fmt.Sprintf("%s-%s", DriverName, Version) } -func (d *driver) GetPidsForContainer(id string) ([]int, error) { +// GetPidsForContainer implements the exec driver Driver interface. +func (d *Driver) GetPidsForContainer(id string) ([]int, error) { d.Lock() active := d.activeContainers[id] d.Unlock() @@ -317,22 +332,24 @@ func (d *driver) GetPidsForContainer(id string) ([]int, error) { return active.Processes() } -func (d *driver) cleanContainer(id string) error { +func (d *Driver) cleanContainer(id string) error { d.Lock() delete(d.activeContainers, id) d.Unlock() return os.RemoveAll(filepath.Join(d.root, id)) } -func (d *driver) createContainerRoot(id string) error { +func (d *Driver) createContainerRoot(id string) error { return os.MkdirAll(filepath.Join(d.root, id), 0655) } -func (d *driver) Clean(id string) error { +// Clean implements the exec driver Driver interface. +func (d *Driver) Clean(id string) error { return os.RemoveAll(filepath.Join(d.root, id)) } -func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) { +// Stats implements the exec driver Driver interface. +func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) { d.Lock() c := d.activeContainers[id] d.Unlock() @@ -357,10 +374,12 @@ func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) { }, nil } +// TtyConsole implements the exec driver Terminal interface. type TtyConsole struct { console libcontainer.Console } +// NewTtyConsole returns a new TtyConsole struct. func NewTtyConsole(console libcontainer.Console, pipes *execdriver.Pipes) (*TtyConsole, error) { tty := &TtyConsole{ console: console, @@ -374,10 +393,12 @@ func NewTtyConsole(console libcontainer.Console, pipes *execdriver.Pipes) (*TtyC return tty, nil } +// Resize implements Resize method of Terminal interface func (t *TtyConsole) Resize(h, w int) error { return term.SetWinsize(t.console.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) } +// AttachPipes attaches given pipes to TtyConsole func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error { go func() { if wb, ok := pipes.Stdout.(interface { @@ -400,6 +421,7 @@ func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error { return nil } +// Close implements Close method of Terminal interface func (t *TtyConsole) Close() error { return t.console.Close() } diff --git a/daemon/execdriver/native/driver_unsupported.go b/daemon/execdriver/native/driver_unsupported.go index 97839cf3b2..f4ca76ff06 100644 --- a/daemon/execdriver/native/driver_unsupported.go +++ b/daemon/execdriver/native/driver_unsupported.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/daemon/execdriver" ) +// NewDriver returns a new native driver, called from NewDriver of execdriver. func NewDriver(root, initPath string) (execdriver.Driver, error) { return nil, fmt.Errorf("native driver not supported on non-linux") } diff --git a/daemon/execdriver/native/driver_unsupported_nocgo.go b/daemon/execdriver/native/driver_unsupported_nocgo.go index 2b8e9f81a1..757845661b 100644 --- a/daemon/execdriver/native/driver_unsupported_nocgo.go +++ b/daemon/execdriver/native/driver_unsupported_nocgo.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/daemon/execdriver" ) +// NewDriver returns a new native driver, called from NewDriver of execdriver. func NewDriver(root, initPath string) (execdriver.Driver, error) { return nil, fmt.Errorf("native driver not supported on non-linux") } diff --git a/daemon/execdriver/native/exec.go b/daemon/execdriver/native/exec.go index 47f812ed22..a52bd8f1b8 100644 --- a/daemon/execdriver/native/exec.go +++ b/daemon/execdriver/native/exec.go @@ -10,12 +10,17 @@ import ( "github.com/docker/docker/daemon/execdriver" "github.com/opencontainers/runc/libcontainer" + // Blank import 'nsenter' so that init in that package will call c + // function 'nsexec()' to do 'setns' before Go runtime take over, + // it's used for join to exist ns like 'docker exec' command. _ "github.com/opencontainers/runc/libcontainer/nsenter" "github.com/opencontainers/runc/libcontainer/utils" ) +// Exec implements the exec driver Driver interface, +// it calls libcontainer APIs to execute a container. // TODO(vishh): Add support for running in privileged mode. -func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { +func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { active := d.activeContainers[c.ID] if active == nil { return -1, fmt.Errorf("No active container exists with ID %s", c.ID) diff --git a/daemon/execdriver/native/info.go b/daemon/execdriver/native/info.go index 9d7342da86..498e56f00e 100644 --- a/daemon/execdriver/native/info.go +++ b/daemon/execdriver/native/info.go @@ -4,7 +4,7 @@ package native type info struct { ID string - driver *driver + driver *Driver } // IsRunning is determined by looking for the diff --git a/daemon/execdriver/pipes.go b/daemon/execdriver/pipes.go index 158219f0c5..fdddaee9b0 100644 --- a/daemon/execdriver/pipes.go +++ b/daemon/execdriver/pipes.go @@ -4,13 +4,14 @@ import ( "io" ) -// Pipes is a wrapper around a containers output for +// Pipes is a wrapper around a container's output for // stdin, stdout, stderr type Pipes struct { Stdin io.ReadCloser Stdout, Stderr io.Writer } +// NewPipes returns a wrapper around a container's output func NewPipes(stdin io.ReadCloser, stdout, stderr io.Writer, useStdin bool) *Pipes { p := &Pipes{ Stdout: stdout, diff --git a/daemon/execdriver/termconsole.go b/daemon/execdriver/termconsole.go index 4dc18e5703..900040570b 100644 --- a/daemon/execdriver/termconsole.go +++ b/daemon/execdriver/termconsole.go @@ -5,9 +5,11 @@ import ( "os/exec" ) +// StdConsole defines standard console operations for execdriver type StdConsole struct { } +// NewStdConsole returns a new StdConsole struct func NewStdConsole(processConfig *ProcessConfig, pipes *Pipes) (*StdConsole, error) { std := &StdConsole{} @@ -17,6 +19,7 @@ func NewStdConsole(processConfig *ProcessConfig, pipes *Pipes) (*StdConsole, err return std, nil } +// AttachPipes attaches given pipes to exec.Cmd func (s *StdConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error { command.Stdout = pipes.Stdout command.Stderr = pipes.Stderr @@ -35,11 +38,13 @@ func (s *StdConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error { return nil } +// Resize implements Resize method of Terminal interface func (s *StdConsole) Resize(h, w int) error { // we do not need to reside a non tty return nil } +// Close implements Close method of Terminal interface func (s *StdConsole) Close() error { // nothing to close here return nil diff --git a/daemon/execdriver/utils.go b/daemon/execdriver/utils.go index fd5a270552..4231ebf542 100644 --- a/daemon/execdriver/utils.go +++ b/daemon/execdriver/utils.go @@ -30,17 +30,24 @@ func init() { } type ( + // CapabilityMapping maps linux capability name to its value of capability.Cap type + // Capabilities is one of the security systems in Linux Security Module (LSM) + // framework provided by the kernel. + // For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html CapabilityMapping struct { Key string `json:"key,omitempty"` Value capability.Cap `json:"value,omitempty"` } + // Capabilities contains all CapabilityMapping Capabilities []*CapabilityMapping ) +// String returns of CapabilityMapping func (c *CapabilityMapping) String() string { return c.Key } +// GetCapability returns CapabilityMapping which contains specific key func GetCapability(key string) *CapabilityMapping { for _, capp := range capabilityList { if capp.Key == key { @@ -51,6 +58,7 @@ func GetCapability(key string) *CapabilityMapping { return nil } +// GetAllCapabilities returns all of the capabilities func GetAllCapabilities() []string { output := make([]string, len(capabilityList)) for i, capability := range capabilityList { @@ -59,6 +67,8 @@ func GetAllCapabilities() []string { return output } +// TweakCapabilities can tweak capabilities by adding or dropping capabilities +// based on the basics capabilities. func TweakCapabilities(basics, adds, drops []string) ([]string, error) { var ( newCaps []string diff --git a/daemon/execdriver/windows/unsupported.go b/daemon/execdriver/windows/unsupported.go index 0a492e1267..89be21f9a9 100644 --- a/daemon/execdriver/windows/unsupported.go +++ b/daemon/execdriver/windows/unsupported.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/daemon/execdriver" ) +// NewDriver returns a new execdriver.Driver func NewDriver(root, initPath string) (execdriver.Driver, error) { return nil, fmt.Errorf("Windows driver not supported on non-Windows") }